home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / tcp_ip / wnos / wn941101 / mailbox.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-10-07  |  66.8 KB  |  2,826 lines

  1. /* There are only two functions in this mailbox code that depend on the
  2.  * underlying protocol, namely mbx_getname() and dochat(). All the other
  3.  * functions can hopefully be used without modification on other stream
  4.  * oriented protocols than AX.25 or NET/ROM.
  5.  *
  6.  * SM0RGV 890506, most work done previously by W9NK
  7.  *
  8.  *** Changed 900114 by KA9Q to use newline mapping features in stream socket
  9.  *      interface code; everything here uses C eol convention (\n)
  10.  *
  11.  *      Numerous new commands and other changes by SM0RGV, 900120
  12.  */
  13. #include <stdio.h>
  14. #include <time.h>
  15. #include <ctype.h>
  16. #ifdef  UNIX
  17. #include <sys/types.h>
  18. #include <sys/stat.h>
  19. #endif
  20. #include <io.h>
  21. #include "global.h"
  22. #include "config.h"
  23. #include "bm.h"
  24. #include "timer.h"
  25. #include "mailbox.h"
  26. #include "cmdparse.h"
  27. #include "proc.h"
  28. #include "socket.h"
  29. #include "usock.h"
  30. #include "session.h"
  31. #include "ax25.h"
  32. #include "smtp.h"
  33. #include "dirutil.h"
  34. #include "telnet.h"
  35. #include "ftp.h"
  36. #include "ftpserv.h"
  37. #include "netrom.h"
  38. #include "commands.h"
  39. #include "netuser.h"
  40. #include "files.h"
  41.  
  42. #define MAX_MBXERR      5               /* a try to stop endless "Huh?" or "Error ?" */
  43. // #define RMNCSYS 17034
  44. extern char RouteHeader[];
  45. static int Stelnet = -1;
  46. /* extern int dumproute __ARGS((struct route *rp,char *p)); */
  47.  
  48. #ifdef  NETROM
  49. #define STACKSIZE   3072
  50. static int Nrsocket = -1;
  51. #else
  52. #define STACKSIZE       2048
  53. #endif
  54.  
  55. extern char No[];
  56.  
  57. struct mbx *Mbox[NUMMBX];
  58. static int MAttended = 1;       /* default to attended mode */
  59. static int ThirdParty = 1;      /* default to thirdparty mail allowed */
  60. unsigned Maxlet = BM_NLET;
  61. #ifdef XXX
  62. unsigned Tiptimeout = 180;  /* Default tip inactivity timeout (seconds) */
  63. #endif
  64. int Mbmore = 0;
  65. int bbsUsers;
  66.  
  67. static int Areawait = 0;
  68.  
  69. char Banner[] = "[WNOS-H$]\n";
  70. static char Noperm[] = "Permission denied\n";
  71.  
  72. static char *MBlogname = NULLCHAR;
  73. static char *MHostname = NULLCHAR;
  74. static char MBHostname[30] = "\0";
  75. static char MMotd[256] = "\0";
  76. static char Mbbanner[] = "'s TCP/IP system.";
  77. static char number[7];
  78. static char Loginbanner[] = "WNOS (%s)\n";
  79. static char Howtoend[] = "Terminate with /EX or ^Z in first column (^A aborts)\n";
  80. static char Aborted[] = "*** aborted\n";
  81. static char mbnrid[20] = "\0";
  82. #if (!defined(AX25) || defined(NETROM))
  83. static char Noserv[] = "Service unavailable\n";
  84. #endif
  85. #ifdef XXX
  86. static int dombiproute __ARGS((int argc,char *argv[],void *p)); 
  87. #endif
  88. static int doattend __ARGS((int argc,char *argv[],void *p));
  89. static int dofinfo __ARGS((int argc,char *argv[],void *p));
  90. static int dofnic __ARGS((int argc,char *argv[],void *p));
  91. static int domblog __ARGS((int argc,char *argv[],void *p));
  92. static int domaxmsg __ARGS((int argc,char *argv[],void *p));
  93. static int dombmotd __ARGS((int argc,char *argv[],void *p));
  94. static int dombmore __ARGS((int argc,char *argv[],void *p));
  95. static int dosend __ARGS((int argc,char *argv[],void *p));
  96. static int dosid __ARGS((int argc,char *argv[],void *p));
  97. #ifdef XXX
  98. static int dotimeout __ARGS((int argc,char *argv[],void *p));
  99. #endif
  100. static int dombescape __ARGS((int argc,char *argv[],void *p));
  101. #ifdef AX25
  102. static int dombheard __ARGS((int argc,char *argv[],void *p));
  103. #endif
  104. static int dodownload __ARGS((int argc,char *argv[],void *p));
  105. static int dombupload __ARGS((int argc,char *argv[],void *p));
  106. static int dowhat __ARGS((int argc,char *argv[],void *p));
  107. static int dosysop __ARGS((int argc,char *argv[],void *p));
  108. static int dostars __ARGS((int argc,char *argv[],void *p));
  109. static int doarea __ARGS((int argc,char *argv[],void *p));
  110. static int dombhelp __ARGS((int argc,char *argv[],void *p));
  111. static int dogateway __ARGS((int argc,char *argv[],void *p));
  112. static int dombhostname __ARGS((int argc,char *argv[],void *p));
  113. static int dombtelnet __ARGS((int argc,char *argv[],void *p));
  114. #ifdef CONVERS
  115. static int dombconvers __ARGS((int argc,char *argv[],void *p));
  116. #endif
  117. static int dombfinger __ARGS((int argc,char *argv[],void *p));
  118. #ifdef AX25
  119. static int dombroute __ARGS((int argc,char *argv[],void *p));
  120. #endif
  121. static int dombstat __ARGS((int argc,char *argv[],void *p));
  122. static int dombuser __ARGS((int argc,char *argv[],void *p));
  123. #ifdef  NETROM
  124. static int dombnrconnect __ARGS((int argc,char *argv[],void *p));
  125. static int dombnodes __ARGS((int argc,char *argv[],void *p));
  126. #endif
  127. static void gw_alarm __ARGS((void *p));
  128. static int near mbx_getname __ARGS((struct mbx *m));
  129. static int near mbxrecvline __ARGS((int s,char *buf,int len,int escape));
  130. static int near gw_connect __ARGS((struct mbx *m,int s,char *fsocket,int len));
  131. static void gw_input __ARGS((int s,void *notused,void *p));
  132. static void gw_superv __ARGS((int null,void *proc,void *p));
  133. static int near mbx_to __ARGS((int argc,char *argv[],void *p));
  134. static int near mbx_data __ARGS((struct mbx *m,struct list *cclist,char *extra));
  135. static int near msgidcheck __ARGS((char *string));
  136. static int near uuencode __ARGS((FILE *infile,int s,char *infilename));
  137. static int thirdparty __ARGS((struct mbx *m));
  138. int setuns __ARGS((unsigned *var,char *label,int argc,char *argv[]));
  139.  
  140. static struct cmds near Mbcmds[] = {                    /* TEST */
  141.     "",         doreadnext,     0, 0, NULLCHAR,
  142.     "area",         doarea,                 0, 0, NULLCHAR,
  143.     "bye ",         domboxbye,              0, 0, NULLCHAR,
  144.     "chat",         dogateway,              0, 0, NULLCHAR,
  145.     "connect",      dogateway,              0, 0, NULLCHAR,
  146. #ifdef CONVERS
  147.     "convers",      dombconvers,    0, 0, NULLCHAR,
  148. #endif
  149.     "download",     dodownload,             0, 2, "d[u] file",
  150.     "escape",       dombescape,             0, 0, NULLCHAR,
  151.     "finger",       dombfinger,             0, 0, NULLCHAR,
  152.     "help",         dombhelp,               0, 0, NULLCHAR,
  153.     "info",         dombhelp,               0, 0, NULLCHAR,
  154. #ifdef XXX
  155.     "iproute",      dombiproute,            0, 0, NULLCHAR,
  156. #endif
  157.     "kill",         dodelmsg,               0, 2, "k #",
  158.     "list",         dolistnotes,    0, 0, NULLCHAR,
  159. #ifdef  AX25
  160.     "mheard",       dombheard,              0, 0, NULLCHAR,
  161. #endif
  162. #ifdef  NETROM
  163.     "nodes",        dombnodes,              0, 0, NULLCHAR,
  164.     "nconnect",     dombnrconnect,  0, 2, "nc call|node",
  165. #endif
  166. #ifdef AX25
  167.     "path",         dombroute,              0, 0, NULLCHAR,
  168. #endif
  169.     "quit",         domboxbye,              0, 0, NULLCHAR,
  170.     "read",         doreadmsg,              0, 2, "r #",
  171.     "send",         dosend,                 0, 0, NULLCHAR,
  172.     "telnet",       dombtelnet,             0, 2, "t host",
  173.     "user",         dombuser,               0, 0, NULLCHAR,
  174.     "upload",       dombupload,             0, 2, "u file",
  175.     "what",         dowhat,                 0, 0, NULLCHAR,
  176.     "?   ",         dombhelp,               0, 0, NULLCHAR,
  177. /* cmds down here are not displayed by the "?" cmd */
  178.     "os",           dombstat,               0, 0, NULLCHAR,
  179.     "[",            dosid,                  0, 0, NULLCHAR,
  180. #ifdef  AX25
  181.     "f>",           dorevfwd,               0, 0, NULLCHAR,
  182. #endif
  183.     "@",            dosysop,                0, 0, NULLCHAR,
  184.     "v",            doreadmsg,              0, 2, "v #",
  185.     "xr",           dombhostname,   0, 0, NULLCHAR,
  186.     "***",          dostars,                0, 0, NULLCHAR,
  187.     NULLCHAR,   NULLFP,         0, 0, "\n*** invalid command\n",
  188. };
  189.  
  190. #ifdef  AX25
  191. int
  192. ax25start(argc,argv,p)
  193. int argc;
  194. char *argv[];
  195. void *p;
  196. {
  197.     int s, type;
  198.  
  199.     if (Axi_sock != -1)
  200.         return 0;
  201.  
  202.     psignal(Curproc,0);     /* Don't keep the parser waiting */
  203.     chname(Curproc,"AX25 listener");
  204.     Axi_sock = socket(AF_AX25,SOCK_STREAM,0);
  205.     /* bind() is done automatically */
  206.     listen(Axi_sock,1);
  207.  
  208.     for(;;){
  209.         if((s = accept(Axi_sock,NULLCHAR,NULLINT)) == -1)
  210.             break;  /* Service is shutting down */
  211.         type = AX25TNC;
  212.         /* Eat the line that triggered the connection
  213.          * and then start the mailbox
  214.          */
  215.         sockmode(s,SOCK_ASCII); /* To make recvline work */
  216.         recvline(s,NULLCHAR,80);
  217.         newproc("mbox",STACKSIZE,mbx_incom,s,(void *)type,NULL,0);
  218.     }
  219.     return 0;
  220. }
  221.  
  222. int
  223. ax250(argc,argv,p)
  224. int argc;
  225. char *argv[];
  226. void *p;
  227. {
  228.     close_s(Axi_sock);
  229.     Axi_sock = -1;
  230.     return 0;
  231. }
  232. #endif
  233.  
  234. /* Start up Telnet server */
  235. int
  236. telnet1(argc,argv,p)
  237. int argc;
  238. char *argv[];
  239. void *p;
  240. {
  241.     struct sockaddr_in lsocket;
  242.     int s;
  243.  
  244.     if(Stelnet != -1){
  245.         return 0;
  246.     }
  247.     psignal(Curproc,0);     /* Don't keep the parser waiting */
  248.     chname(Curproc,"Telnet listener");
  249.  
  250.     lsocket.sin_family = AF_INET;
  251.     lsocket.sin_addr.s_addr = INADDR_ANY;
  252.     lsocket.sin_port = (argc < 2) ? IPPORT_TELNET : atoi(argv[1]);
  253.  
  254.     Stelnet = socket(AF_INET,SOCK_STREAM,0);
  255.     bind(Stelnet,(char *)&lsocket,sizeof(lsocket));
  256.  
  257.     listen(Stelnet,1);
  258.  
  259.     for(;;){
  260.         if((s = accept(Stelnet,NULLCHAR,NULLINT)) == -1)
  261.             break;  /* Service is shutting down */
  262.         if(availmem() < Memthresh){
  263.             usputs(s,Nospace);
  264.             shutdown(s,1);
  265.         } else {
  266.             /* Spawn a server */
  267.             int type = TELNET;
  268.             newproc("mbox",STACKSIZE,mbx_incom,s,(void *)type,NULL,0);
  269.         }
  270.     }
  271.     return 0;
  272. }
  273.  
  274. /* Stop telnet server */
  275. int
  276. telnet0(argc,argv,p)
  277. int argc;
  278. char *argv[];
  279. void *p;
  280. {
  281.     close_s(Stelnet);
  282.     Stelnet = -1;
  283.     return 0;
  284. }
  285.  
  286. #ifdef  NETROM
  287. int
  288. nr4start(argc,argv,p)
  289. int argc;
  290. char *argv[];
  291. void *p;
  292. {
  293.     int s, type;
  294.  
  295.     if (Nrsocket != -1)
  296.         return 0;
  297.  
  298.     psignal(Curproc,0);     /* Don't keep the parser waiting */
  299.     chname(Curproc,"NETROM listener");
  300.     Nrsocket = socket(AF_NETROM,SOCK_SEQPACKET,0);
  301.     /* bind() is done automatically */
  302.  
  303.     listen(Nrsocket,1);
  304.  
  305.     for(;;){
  306.         if((s = accept(Nrsocket,NULLCHAR,NULLINT)) == -1)
  307.             break;  /* Service is shutting down */
  308.         type = NRSESSION;
  309.         newproc("mbox",STACKSIZE,mbx_incom,s,(void *)type,NULL,0);
  310.     }
  311.     return 0;
  312. }
  313.  
  314. int
  315. nr40(argc,argv,p)
  316. int argc;
  317. char *argv[];
  318. void *p;
  319. {
  320.     close_s(Nrsocket);
  321.     Nrsocket = -1;
  322.     return 0;
  323. }
  324. #endif
  325.  
  326. #if     defined(ANSIPROTO)
  327. static void near
  328. logmb(int s,char *fmt, ...)
  329. {
  330.     va_list ap;
  331.     char *cp;
  332.     long t;
  333.     int i;
  334.     struct sockaddr fsocket;
  335.     FILE *MBLogfp;
  336.  
  337.     if(MBlogname == NULLCHAR
  338.       || (MBLogfp = open_file(MBlogname,APPEND_TEXT,0,1)) == NULLFILE)
  339.         return;
  340.  
  341.     time(&t);
  342.     cp = ctime(&t);
  343.     rip(cp);
  344.     i = SOCKSIZE;
  345.     fprintf(MBLogfp,"%s",cp);
  346.     if(getpeername(s,(char *)&fsocket,&i) != -1)
  347.         fprintf(MBLogfp," %s",psocket(&fsocket));
  348.  
  349.     fprintf(MBLogfp," - MBOX ");
  350.     va_start(ap,fmt);
  351.     vfprintf(MBLogfp,fmt,ap);
  352.     va_end(ap);
  353.     fprintf(MBLogfp,"\n");
  354.     fclose(MBLogfp);
  355. }
  356. #else
  357. /*VARARGS2*/
  358. static void near
  359. logmb(s,fmt,arg1,arg2,arg3,arg4,arg5)
  360. int s;
  361. char *fmt;
  362. int arg1,arg2,arg3,arg4,arg5;
  363. {
  364.     char *cp;
  365.     long t;
  366.     int i;
  367.     struct sockaddr fsocket;
  368.     FILE *MBLogfp;
  369.  
  370.     if(MBlogname == NULLCHAR
  371.       || (MBLogfp = open_file(MBlogname,APPEND_TEXT,0,1)) == NULLFILE)
  372.         return;
  373.  
  374.     time(&t);
  375.     cp = ctime(&t);
  376.     rip(cp);
  377.     i = SOCKSIZE;
  378.     fprintf(MBLogfp,"%s",cp);
  379.     if(getpeername(s,(char *)&fsocket,&i) != -1)
  380.         fprintf(MBLogfp," %s",psocket(&fsocket));
  381.  
  382.     fprintf(MBLogfp," - ");
  383.     fprintf(MBLogfp,fmt,arg1,arg2,arg3,arg4,arg5);
  384.     fprintf(MBLogfp,"\n");
  385.     fclose(MBLogfp);
  386. }
  387. #endif
  388.  
  389. int
  390. dombox(argc,argv,p)
  391. int argc;
  392. char *argv[];
  393. void *p;
  394. {
  395.     /* mbox subcommand table */
  396.     struct cmds Mbtab[] = {
  397.         "attend",               doattend,               0, 0, NULLCHAR,
  398. #ifdef  AX25
  399.         "finfo",                dofinfo,                0, 0, NULLCHAR,
  400.         "fkick",                dombkick,               0, 0, NULLCHAR,
  401.         "fnic",                 dofnic,                 0, 0, NULLCHAR,
  402.         "ftimer",               dombtimer,              0, 0, NULLCHAR,
  403. #endif
  404.         "log",                  domblog,                0, 0, NULLCHAR,
  405.         "maxmsg",               domaxmsg,               0, 0, NULLCHAR,
  406.         "motd",                 dombmotd,               0, 0, NULLCHAR,
  407.         "more",                 dombmore,               0, 0, NULLCHAR,
  408.         "remote",               dombhostname,   0, 0, NULLCHAR,
  409.         "status",               domboxdisplay,  0, 0, NULLCHAR,
  410. #ifdef XXX
  411.         "tiptimeout",   dotimeout,              0, 0, NULLCHAR,
  412. #endif
  413.         "user",                 dombuser,               0, 0, NULLCHAR,
  414.         NULLCHAR,
  415.     };
  416.     return subcmd(Mbtab,argc,argv,p);
  417. }
  418.  
  419. static int
  420. doattend(argc,argv,p)
  421. int argc;
  422. char *argv[];
  423. void *p;
  424. {
  425.     return setbool(&MAttended,"Mbox attended",argc,argv);
  426. }
  427.  
  428. /* Set the Info field of R: header (eg forward info "[Bath, Avon - WNOS3]") */
  429. static int
  430. dofinfo( argc, argv,p)
  431. int argc;
  432. char *argv[];
  433. void *p;
  434. {
  435.     extern char *FInfo;
  436.  
  437.     if(argc < 2 && FInfo != NULLCHAR)
  438.         tprintf("FBBS Info: %s\n", FInfo);
  439.     else {
  440.         if (FInfo != NULLCHAR)
  441.             xfree(FInfo);
  442.         FInfo = mxallocw(25);
  443.         sprintf(FInfo,"%.24s",argv[1]);
  444.     }
  445.     return 0;
  446. }
  447.  
  448. /* Set Nic field of R: header (eg forward nic ".GB7IMB.#41.GBR.EU" */
  449. static int
  450. dofnic(argc,argv,p)
  451. int argc;
  452. char *argv[];
  453. void *p;
  454. {
  455.     extern char *FNic;
  456.  
  457.     if(argc < 2 && FNic != NULLCHAR)
  458.         tprintf("FNIC id: %s\n", FNic);
  459.     else {
  460.         if(FNic != NULLCHAR)
  461.             xfree(FNic);
  462.         FNic = mxallocw(25);
  463.         sprintf(FNic,"%.24s",argv[1]);
  464.     }
  465.     return 0;
  466. }
  467.  
  468. static int
  469. domblog(argc,argv,p)
  470. int argc;
  471. char *argv[];
  472. void *p;
  473. {
  474.     if(argc < 2){
  475.         if(MBlogname != NULLCHAR)
  476.             tprintf("MBLog to %s\n",MBlogname);
  477.         else
  478.             tputs("MBLog off\n");
  479.     } else {
  480.         if(MBlogname != NULLCHAR) {
  481.             xfree(MBlogname);
  482.             MBlogname = NULLCHAR;
  483.         }
  484.         if(strcmp(argv[1],"off") != 0)
  485.             MBlogname = strxdup(Mboxlog);
  486.     }
  487.     return 0;
  488. }
  489.  
  490. static int
  491. domaxmsg(argc,argv,p)
  492. int argc;
  493. char *argv[];
  494. void *p;
  495. {
  496.     return setuns(&Maxlet,"Max msgs per area",argc,argv);
  497. }
  498.  
  499. #ifdef XXX
  500. static int
  501. dotimeout(argc,argv,p)
  502. int argc;
  503. char *argv[];
  504. void *p;
  505. {
  506.     return setuns(&Tiptimeout,"Tip conn timeout",argc,argv);
  507. }
  508. #endif
  509.  
  510. static int
  511. dombmore(argc,argv,p)
  512. int argc;
  513. char *argv[];
  514. void *p;
  515. {
  516.     return setbool(&Mbmore,"Mbox more",argc,argv);
  517. }
  518.  
  519. static int
  520. dombmotd(argc,argv,p)
  521. int argc;
  522. char *argv[];
  523. void *p;
  524. {
  525.     int i;
  526.  
  527.     if(argc < 2 && MMotd[0] != '\0')
  528.         tputs(MMotd);
  529.     else {
  530.         MMotd[0] = '\0';
  531.  
  532.         for(i = 1; i < argc; i++) {
  533.             strcat(MMotd,argv[i]);
  534.             if(strlen(MMotd) > 220)
  535.                 break;
  536.             strcat(MMotd," ");
  537.         }
  538.         if(strlen(MMotd) > 2)
  539.             strcat(MMotd,"\n\0");
  540.         else
  541.             MMotd[0] = '\0';
  542.     }
  543.     return 0;
  544. }
  545.  
  546. static int
  547. dombhostname(argc,argv,p)
  548. int argc;
  549. char *argv[];
  550. void *p;
  551. {
  552.     struct mbx *m = (struct mbx *) p;
  553.  
  554.     if(*argv[0] == 'x')
  555.         if(!(m->privs & SYSOP_CMD))
  556.             return -3;
  557.  
  558.     if(argc < 2 && MHostname != NULLCHAR) {
  559.         tprintf("%s\n",MHostname);
  560.     } else {
  561.         if(MHostname != NULLCHAR)
  562.             xfree(MHostname);
  563.         MHostname = strxdup(argv[1]);
  564.     }
  565.     return 0;
  566. }
  567.  
  568. static int
  569. domboxdisplay(argc,argv,p)
  570. int argc;
  571. char *argv[];
  572. void *p;
  573. {
  574.     int i, j, len;
  575.     struct mbx *m;
  576.     char fsocket[MAXSOCKSIZE], *states[] =
  577.         {"LOGIN","CMD","SUBJ","DATA","REVFWD","TRYING","FORWARD","CONVERS"};
  578.  
  579.     tputs("User       State    S#  Where\n");
  580.     for (i = 0; i < NUMMBX; i++) {
  581.         if((m = Mbox[i]) != NULLMBX) {
  582.             len = MAXSOCKSIZE;
  583.             j = getpeername(m->user,fsocket,&len);
  584.             tprintf("%-11s%-9s%-4u%s\n",
  585.               m->name,
  586.               states[m->state],
  587.               m->user,
  588.               (j != -1) ? psocket(fsocket) : "");
  589.         }
  590.     }
  591.     return 0;
  592. }
  593.  
  594. struct mbx *
  595. newmbx()
  596. {
  597.     int i;
  598.     struct mbx *m;
  599.  
  600.     for(i = 0; i < NUMMBX; i++){
  601.         if(Mbox[i] == NULLMBX){
  602.             m = Mbox[i] = (struct mbx *)mxallocw(sizeof(struct mbx));
  603.        bbsUsers++;
  604.         m->mbnum = i;
  605.             return m;
  606.     }
  607.     }
  608.     /* If we get here, there are no free mailbox sessions */
  609.     return NULLMBX;
  610. }
  611.  
  612. /* Incoming mailbox session */
  613. static void
  614. mbx_incom(s,t,p)
  615. int s;
  616. void *t;
  617. void *p;
  618. {
  619.     struct mbx *m;
  620.     struct usock *up;
  621.     int rval;
  622.     char *cp, *cp1, *buf[3], buf2[77], buf3[77];
  623.     FILE *fp;
  624.  
  625.     sockmode(s,SOCK_ASCII);
  626.     sockowner(s,Curproc);   /* We own it now */
  627.     close_s(Curproc->output);
  628.     close_s(Curproc->input);
  629.     Curproc->output = Curproc->input = s;
  630.  
  631.     if((m = newmbx()) == NULLMBX){
  632.         usputs(s,Nosess);
  633.         return;
  634.     }
  635.     setflush(s,-1);
  636.  
  637.     m->user = s;
  638.     m->escape = 24;         /* default escape character is Ctrl-X */
  639.     m->type = (int) t;
  640.  
  641.     /* get the name of the remote station */
  642.     if(mbx_getname(m) == -1) {
  643.         exitbbs(m);
  644.         return;
  645.     }
  646. #ifdef NETROM
  647.     if(Nrifaces[0].alias != NULLCHAR) {
  648.         cp = strxdup(Nrifaces[0].alias);
  649.         if((cp1 = strchr(cp,' ')) != NULLCHAR)
  650.             *cp1 = '\0';
  651.         sprintf(mbnrid,"%s:%s> ",cp,pax25(m->line,Nrifaces[0].iface->hwaddr));
  652.         xfree(cp);
  653.     } else
  654. #endif
  655.     mbnrid[0] = '\0';
  656.  
  657.     sprintf(MBHostname,"%.28s",Hostname);
  658.     if((cp = strchr(MBHostname,'.')) != NULLCHAR)
  659.         *cp = '\0';
  660.     strupr(MBHostname);
  661.     m->state = MBX_CMD;     /* start in command state */
  662.  
  663. // DL8YQ        /* Now say hi */
  664.     cp='\0';
  665.     cp=strxdup(m->name);
  666.     if((fp = fopen(Bbsfile,READ_TEXT)) != NULLFILE){
  667.  
  668.     while (fgets(buf2,LINELEN,fp),!feof(fp)){
  669.         if (buf2[0] == '#')
  670.         continue;
  671.  
  672.     buf2[strlen(buf2)-1]=0;
  673.     if(strcmp(buf2,cp) == 0){
  674.     usprintf(m->user,"%s %s\n",Hostname,Mbbanner);
  675.     usflush(m->user);
  676.     pause(3000L);
  677.     usprintf(m->user,Banner);
  678.     usflush(m->user);
  679.     pause(4000L);
  680.     break;
  681.  
  682.         }
  683.     }
  684. }
  685.     fclose(fp);
  686.     strcpy(buf3,buf2);
  687.     if(strcmp(buf2,cp) != 0){
  688.     usprintf(m->user,"Welcome %s at %s %s Currently %d user%s\n",cp,Hostname,Mbbanner,bbsUsers,bbsUsers == 1 ? "" : "s");
  689.     sprintf(buf2,"%s/host.hlp",Helpdir);
  690.     if((fp = fopen(buf2,READ_TEXT)) != NULLFILE) {
  691.         usputs(m->user,"\n");
  692.         sendfile(fp,m->user,ASCII_TYPE,0);
  693.         fclose(fp);
  694.     } else
  695.     usputs(m->user,"Type '?' for help.\n");
  696.  
  697.     if(MMotd != NULLCHAR)
  698.         usprintf(m->user,"%s\n",MMotd);
  699.     usprintf(m->user,"Login at %s\n",ptime(&currtime));
  700.     usprintf(m->user,"Prog. runtime: %s  (%lu Byte coreleft)\n\n",tformat(secclock()),availmem());
  701. }
  702.     /* Enable our local message area */
  703.     buf[1] = m->name;
  704.  
  705.     doarea(2,buf,m);
  706.  
  707.     cp1 = strxdup(m->name);
  708.     strupr(cp1);
  709.     // >muss hinter dem %s
  710.     if (strcmp(buf3,cp) == 0){
  711.     usprintf(m->user,">\r");
  712.     xfree(cp);
  713.     }
  714.     else
  715.     usprintf(m->user,"(%s) %s de %s>\n",m->narea,cp1,MBHostname);
  716.     while(mbxrecvline(s,m->line,MBXLINE,-1) != EOF){
  717.         if((rval = mbx_parse(m)) == -2)
  718.             break;
  719.         if(rval == 1)
  720.             usputs(m->user,"Bad syntax\n");
  721.         if(!(m->sid & MBX_SID) && isnewprivmail(m) > 0L)
  722.             usputs(m->user,"You have new mail\n");
  723.         scanmail(m);
  724.         if(m->sid & MBX_SID)
  725.             usputs(m->user,">\n");
  726.         else
  727.             usprintf(m->user,"(%s) %s de %s>",m->narea,cp1,MBHostname);
  728.  
  729.     m->state = MBX_CMD;
  730.     }
  731.     xfree(cp1);
  732.     exitbbs(m);
  733.     /* nasty hack! we may have screwed up reference count */
  734.     /* by invoking newproc("smtp_send",....); Fudge it!   */
  735.     if((up = itop(Curproc->output)) != NULLUSOCK)
  736.         up->refcnt = 1;
  737.     close_s(Curproc->output);
  738.     return;
  739. }
  740.  
  741. void
  742. exitbbs(m)
  743. struct mbx *m;
  744. {
  745.     closenotes(m);
  746.     xfree(m->to);
  747.     xfree(m->origto);
  748.     xfree(m->tofrom);
  749.     xfree(m->tomsgid);
  750.     if(m->tfile != NULLFILE)
  751.         fclose(m->tfile);
  752.     xfree(m->path);
  753.     if(m->startmsg != NULLCHAR)
  754.         xfree(m->startmsg);
  755.     xfree((char *)m->mbox);
  756. /*    close_s(m->user);
  757.     m->user = -1; */
  758.     Mbox[m->mbnum] = NULLMBX;
  759.     xfree((char *)m);
  760.     smtptick(NULL);
  761.     bbsUsers--;
  762. }
  763.  
  764. /* "twocmds" defines the MBL/RLI two-letter commands, eg. "SB", "SP" and so on.
  765.  * They have to be treated specially since cmdparse() wants a space between
  766.  * the actual command and its arguments.
  767.  * "SP FOO" is converted to "s  foo" and the second command letter is saved
  768.  * in m->stype. Longer commands like "SEND" are unaffected, except for
  769.  * commands starting with "[", i.e. the SID, since we don't know what it will
  770.  * look like.
  771.  */
  772. static char twocmds[] = "slrd[";        /* S,L,R,D are two-letter commands */
  773.  
  774. int
  775. mbx_parse(m)
  776. struct mbx *m;
  777. {
  778.     int i;
  779.     char *cp, *newargv[2];
  780.  
  781.     /* Translate entire buffer to lower case */
  782.     for (cp = m->line; *cp != '\0'; ++cp)
  783.         if(isupper(*cp))
  784.             *cp = tolower(*cp);
  785.     /* Skip any spaces at the begining */
  786.     for(cp = m->line;isspace(*cp);++cp) ;
  787.  
  788.     m->stype = ' ';
  789.  
  790.     if(*cp != '\0' && *(cp+1) != '\0')
  791.         for(i=0; i<strlen(twocmds); ++i){
  792.             if(*cp == twocmds[i] && (isspace(*(cp+2)) || *(cp+2) == '\0'
  793.               || *cp == '[')){
  794.                 if(islower(*(++cp)))
  795.                     m->stype = toupper(*cp); /* Save the second character */
  796.                 else
  797.                     m->stype = *cp;
  798.                 *cp = ' ';
  799.                 break;
  800.             }
  801.         }
  802.  
  803.     /* See if the input line consists solely of digits */
  804.     cp = m->line;
  805.     for(cp = m->line;isspace(*cp);++cp) ;
  806.     newargv[1] = cp;
  807.     for(;*cp != '\0' && isdigit(*cp);++cp) ;
  808.     if(*cp == '\0' && strlen(newargv[1]) > 0) {
  809.         newargv[0] = "read";
  810.         return doreadmsg(2,newargv,(void *)m);
  811.     } else {
  812.         i = cmdparse(Mbcmds,m->line,(void *)m);
  813.         switch(i) {
  814.         case -3:
  815.             tputs(Noperm);
  816.             return 0;
  817.         case -2:
  818.             return -2;
  819.         case -1:
  820.             return (m->err_cnt++ >= MAX_MBXERR) ? -2 : -1;
  821.         default:
  822.             m->err_cnt = 0;
  823.             return i;
  824.         }
  825.     }
  826. }
  827.  
  828. static int near
  829. mbx_getname(m)
  830. struct mbx *m;
  831. {
  832.     union sp sp;
  833.     char *cp, tmp[MAXSOCKSIZE], buf[MBXLINE];
  834.     int anony, oldmode, len = MAXSOCKSIZE;
  835.  
  836.     sp.p = tmp;
  837.     sp.sa->sa_family = AF_LOCAL;    /* default to AF_LOCAL */
  838.     getpeername(m->user,tmp,&len);
  839.     m->path = mxallocw(MBXLINE);
  840.     m->family = sp.sa->sa_family;
  841.  
  842.     /* This is one of the two parts of the mbox code that depends on the
  843.      * underlying protocol. We have to figure out the name of the
  844.      * calling station. This is only practical when AX.25 or NET/ROM is
  845.      * used. Telnet users have to identify themselves by a login procedure.
  846.      */
  847.     switch(sp.sa->sa_family){
  848. #ifdef  AX25
  849.     case AF_NETROM:
  850.     case AF_AX25:
  851.         /* NETROM and AX25 socket address structures are "compatible" */
  852.         addrcp(m->nodename,sp.ax->ax25_addr);
  853.         m->nodename[ALEN] ^= 0x1e;
  854.         pax25(m->name,sp.ax->ax25_addr);
  855.         log(m->user,"MBOX open");
  856.         if((cp = strchr(m->name,'-')) != NULLCHAR)
  857.             *cp = '\0';
  858.  
  859.         /* SMTP wants the name to be in lower case */
  860.         strlwr(m->name);
  861.  
  862.         /* Try to find the privileges of this user from the userfile */
  863.         anony = 1;
  864.         if((m->privs = userlogin(m->name,buf,&m->path,MBXLINE,&anony)) == -1) {
  865.             if((m->privs = userlogin("bbs",buf,&m->path,MBXLINE,&anony)) == -1) {
  866.                 m->privs = 0;
  867.                 xfree(m->path);
  868.                 m->path = NULLCHAR;
  869.             }
  870.         }
  871.         return (m->privs & EXCLUDED_CMD) ? -1 : 0;
  872. #endif
  873.     case AF_LOCAL:
  874.     case AF_INET:
  875.         m->state = MBX_LOGIN;
  876.         usprintf(m->user,Loginbanner,Hostname);
  877.         for(;;){
  878.             usputs(m->user,"Login (Call): ");
  879.             usflush(m->user);
  880.             if(mbxrecvline(m->user,buf,MBXLINE,-1) == EOF)
  881.                 return -1;
  882.             if(*buf == '\0')
  883.                 continue;
  884.  
  885.             cp = buf;
  886.             while(isspace(*cp)) cp++;
  887.             sprintf(m->name,"%.19s",cp);
  888.  
  889. #ifdef AX25
  890.             if(setcall(m->nodename,m->name) == -1)
  891.                 addrcp(m->nodename,Mycall);
  892.  
  893.             m->nodename[ALEN] ^= 0x1e;
  894. #else
  895.             m->nodename[0] = '\0';
  896. #endif
  897.             usprintf(m->user,"Password: %c%c%c",IAC,WILL,TN_ECHO);
  898.             usflush(m->user);
  899.  
  900.             /* SMTP wants the name to be in lower case */
  901.             strlwr(m->name);
  902.  
  903.             oldmode = sockmode(m->user,SOCK_BINARY);
  904.             if(mbxrecvline(m->user,buf,MBXLINE,-1) == EOF)
  905.                 return -1;
  906.             usprintf(m->user,"%c%c%c",IAC,WONT,TN_ECHO);
  907.             sockmode(m->user,oldmode);
  908.             usputs(m->user,"\n");
  909.             usflush(m->user);
  910.             /* This is needed if the password was send before the
  911.              * telnet no-echo options were receied. We neeed to
  912.              * flush the eold sequence from the input buffers, sigh
  913.              */
  914.             if(socklen(m->user,0))          /* discard any remaining input */
  915.                 recv_mbuf(m->user,NULL,0,NULLCHAR,0);
  916.             m->security = 0;
  917.             anony = 0;
  918.             if((m->privs = userlogin(m->name,buf,&m->path,MBXLINE,&anony)) == -1) {
  919.               anony = 1;
  920.               if((m->privs = userlogin("bbs",buf,&m->path,MBXLINE,&anony)) == -1) {
  921.                 m->privs = 0;
  922.                 xfree(m->path);
  923.                 m->path = NULLCHAR;
  924.               }
  925.             }
  926.             log(m->user,"MBOX open %s %s",m->name,anony ? buf : "");
  927.  
  928.             m->security = anony;
  929.             return (m->privs & EXCLUDED_CMD) ? -1 : 0;
  930.         }
  931.     }
  932.     return -1;
  933. }
  934.  
  935. /* This works like recvline(), but telnet options are answered and the
  936.  * terminating newline character is not put into the buffer. If the
  937.  * incoming character equals the value of escape, any queued input is
  938.  * flushed and -2 returned.
  939.  */
  940. static int near
  941. mbxrecvline(s,buf,len,escape)
  942. int s;
  943. char *buf;
  944. int len;
  945. int escape;
  946. {
  947.     int c, cnt = 0, opt;
  948.  
  949.     if(buf == NULLCHAR)
  950.         return 0;
  951.  
  952.     usflush(s);
  953.     while((c = recvchar(s)) != EOF){
  954.         if(c == IAC){           /* Telnet command escape */
  955.             if((c = recvchar(s)) == EOF)
  956.                 break;
  957.             if(c > 250 && c < 255 && (opt = recvchar(s)) != EOF){
  958. #ifdef  foo
  959.                 switch(c){
  960.                 case WILL:
  961.                     usprintf(s,"%c%c%c",IAC,DONT,opt);
  962.                     break;
  963.                 case WONT:
  964.                     usprintf(s,"%c%c%c",IAC,DONT,opt);
  965.                     break;
  966.                 case DO:
  967.                     usprintf(s,"%c%c%c",IAC,WONT,opt);
  968.                     break;
  969.                 case DONT:
  970.                     usprintf(s,"%c%c%c",IAC,WONT,opt);
  971.                 }
  972. #endif
  973. /* to be fixed                  usflush(Curproc->output);*/
  974.                 continue;
  975.             }
  976.             if(c != IAC && opt == EOF)
  977.                 break;
  978.         }
  979.         /* ordinary character */
  980.         if(c == '\r' || c == '\n')
  981.             break;
  982.         if(c == escape){
  983.             if(socklen(s,0)) /* discard any remaining input */
  984.                 recv_mbuf(s,NULL,0,NULLCHAR,0);
  985.             cnt = -2;
  986.             break;
  987.         }
  988.         *buf++ = c;
  989.         ++cnt;
  990.         if(cnt == len - 1)
  991.             break;
  992.     }
  993.     if(c == EOF && cnt == 0)
  994.         return -1;
  995.     *buf = '\0';
  996.     return cnt;
  997. }
  998.  
  999. int
  1000. domboxbye(argc,argv,p)
  1001. int argc;
  1002. char *argv[];
  1003. void *p;
  1004. {
  1005.     struct mbx *m = (struct mbx *) p;
  1006.  
  1007.     /* Now say goodbye */
  1008.     usputs(m->user,"73!\n");
  1009.     usflush(Curproc->output);
  1010.     log(m->user,"MBOX close");
  1011.     return -2;      /* signal that exitbbs() should be called */
  1012. }
  1013.  
  1014. static int
  1015. dombhelp(argc,argv,p)
  1016. int argc;
  1017. char *argv[];
  1018. void *p;
  1019. {
  1020.     char buf[77];
  1021.     int i;
  1022.     FILE *fp;
  1023.     struct mbx *m = (struct mbx *) p;
  1024.  
  1025.     if(*argv[0] == '?') {
  1026.         struct cmds *cmdp;
  1027.  
  1028.         usputs(m->user,"\nAvailable commands:\n");
  1029.  
  1030.         for(i = 0, cmdp = Mbcmds; cmdp->name != NULLCHAR; cmdp++)
  1031.             if(strlen(cmdp->name) > 3) {
  1032.                 usprintf(m->user,"%-15.15s%s",cmdp->name,(i == 4) ? "\n" : "");
  1033.                 i = (i + 1) % 5;
  1034.             }
  1035.         if(i)
  1036.             usputs(m->user,"\n");
  1037.         return 0;
  1038.     }
  1039.     buf[0] = '\0';
  1040.     if(argc > 1) {
  1041.         for(i = 0; Mbcmds[i].name != NULLCHAR; ++i)
  1042.             if(!strncmp(Mbcmds[i].name,argv[1],strlen(argv[1]))) {
  1043.                 sprintf(buf,"%s/%s.hlp",Helpdir,Mbcmds[i].name);
  1044.                 break;
  1045.             }
  1046.     } else
  1047.         sprintf(buf,"%s/%s.hlp",Helpdir,(*argv[0] == 'i') ? "info" : "help");
  1048.  
  1049.     if((fp = fopen(buf,READ_TEXT)) == NULLFILE)
  1050.         usprintf(m->user,"No %s available\n",(*argv[0] == 'i') ? "info" : "help");
  1051.     else {
  1052.         usprintf(m->user,"%s%s\n",
  1053.             (m->family == AF_NETROM) ? mbnrid : "",
  1054.             (*argv[0] == 'i') ? "Info:" : "");
  1055.         sendfile(fp,m->user,ASCII_TYPE,0);
  1056.         usputs(m->user,"\n");
  1057.         fclose(fp);
  1058.     }
  1059.     return 0;
  1060. }
  1061.  
  1062. /* if ThirdParty is not set - restrict the mailbox (S)end command to local only */
  1063. int
  1064. dothirdparty(argc,argv,p)
  1065. int argc;
  1066. char *argv[];
  1067. void *p;
  1068. {
  1069.     return setbool(&ThirdParty,"Third-Party Mail",argc,argv);
  1070. }
  1071.  
  1072. static int
  1073. dosend(argc,argv,p)
  1074. int argc;
  1075. char *argv[];
  1076. void *p;
  1077. {
  1078.     int cccnt = 0, fail = 0;
  1079.     char *host, *cp, fullfrom[MBXLINE], sigwork[LINELEN], *rhdr = NULLCHAR;
  1080.     struct list *ap, *cclist = NULLLIST;
  1081.     FILE *fp;
  1082.  
  1083.     struct mbx *m = (struct mbx *)p;
  1084.  
  1085.     if(m->security == 1)
  1086.         return 0;
  1087.     if((m->stype != 'R' || (m->sid & MBX_SID)) && mbx_to(argc,argv,m) == -1){
  1088.         usputs(m->user,(m->sid & MBX_SID) ? No :
  1089.             "Syntax error:\n"
  1090.             " S[F] name [@ host] [< from_addr] [$bulletin_id]\n"
  1091.             " SR [number]\n");
  1092.         return 0;
  1093.     }
  1094.     if(m->stype != 'R' && msgidcheck(m->tomsgid)) {
  1095.         usprintf(m->user,"%sAlready have %s\n",
  1096.             (m->sid & MBX_SID) ? "NO - ":"",m->tomsgid);
  1097.         return 0;
  1098.     }
  1099.     if(m->stype == 'R' && !(m->sid & MBX_SID) &&
  1100.       mbx_reply(argc,argv,m,&cclist,&rhdr) == -1)
  1101.         return 0;
  1102.     if((cp = rewrite_address(m->to)) != NULLCHAR)
  1103.          if(strcmp(m->to,cp) != 0){
  1104.             m->origto = m->to;
  1105.             m->to = cp;
  1106.          } else
  1107.             xfree(cp);
  1108.  
  1109.     if(!ThirdParty && !(m->privs & SYSOP_CMD))
  1110.         if(thirdparty(m) == 0){
  1111.             usputs(m->user,(m->sid & MBX_SID) ? No : Noperm);
  1112.             return 0;
  1113.         }
  1114.  
  1115.     if((m->origto != NULLCHAR || m->stype == 'R') && !(m->sid & MBX_SID))
  1116.         usprintf(m->user,"To: %s\n", m->to);
  1117.     if(validate_address(m->to) == 0){
  1118.         usputs(m->user,(m->sid & MBX_SID) ? "NO\n" : "Bad user or host name\n");
  1119.         xfree(rhdr);
  1120.         del_list(cclist);
  1121.         /* We don't free any more buffers here. They are freed upon
  1122.          * the next kall to mbx_to() or to domboxbye()
  1123.          */
  1124.         return 0;
  1125.     }
  1126.     /* Display the Cc: line (during SR command) */
  1127.     for(ap = cclist; ap != NULLLIST; ap = ap->next) {
  1128.         if(cccnt == 0){
  1129.             usputs(m->user,Hdrs[CC]);
  1130.             cccnt = 4;
  1131.         }
  1132.         else {
  1133.             usputs(m->user,", ");
  1134.             cccnt += 2;
  1135.         }
  1136.         if(cccnt + strlen(ap->val) > 80 - 3) {
  1137.             usputs(m->user,"\n    ");
  1138.             cccnt = 4;
  1139.         }
  1140.         usputs(m->user,ap->val);
  1141.         cccnt += strlen(ap->val);
  1142.     }
  1143.     if(cccnt)
  1144.         usputs(m->user,"\n");
  1145.     m->state = MBX_SUBJ;
  1146.     if(m->stype != 'R' || (m->sid & MBX_SID) != 0) {
  1147.     usputs(m->user,(m->sid & MBX_SID) ? "OK\n" : " Subject: ");
  1148.         if(mbxrecvline(m->user,m->line,MBXLINE,-1) == -1)
  1149.             return 0;
  1150.     }
  1151.     else                            /* Replying to a message */
  1152.     usprintf(m->user," Subject: %s\n",m->line);
  1153.     if(mbx_data(m,cclist,rhdr) == -1){
  1154.         xfree(rhdr);
  1155.         del_list(cclist);
  1156.         usputs(m->user,(m->sid & MBX_SID) ? "*** NO\n": "Can't create mailfile\n");
  1157.         return 0;
  1158.     }
  1159.     xfree(rhdr);
  1160.     m->state = MBX_DATA;
  1161.     if(!(m->sid & MBX_SID) && m->stype != 'F')
  1162.         usprintf(m->user,"Enter message. %s",Howtoend);
  1163.  
  1164.     if(m->stype != 'F' || (m->sid & MBX_SID)) {
  1165.         while(mbxrecvline(m->user,m->line,MBXLINE,-1) != -1){
  1166.             if(m->line[0] == 0x01){  /* CTRL-A */
  1167.                 fclose(m->tfile);
  1168.                 usputs(m->user,Aborted);
  1169.                 del_list(cclist);
  1170.                 return 0;
  1171.             }
  1172.             if(m->line[0] != CTLZ
  1173.               && stricmp(m->line,"/ex")
  1174.               && stricmp(m->line,"***end")
  1175.               && stricmp(m->line,"."))
  1176.                 fprintf(m->tfile,"%s\n",m->line);
  1177.             else {
  1178.                 if(!(m->sid & MBX_SID))
  1179.                     usputs(m->user,"Message saved\n");
  1180.                 break;  /* all done */
  1181.             }
  1182.         }
  1183.     } else {
  1184.         fputs("----- Forwarded message -----\n\n",m->tfile);
  1185.         msgtofile(m,m->current,m->tfile,0);
  1186.         fputs("----- End of forwarded message -----\n",m->tfile);
  1187.     }
  1188.  
  1189.     /* Insert customised signature if one is found */
  1190.     if(!(m->sid & MBX_SID)) {       /* not a forwarding BBS */
  1191.          sprintf(sigwork,"%s/%s.sig",Signature,
  1192.              m->tofrom ? m->tofrom : m->name);
  1193.          if((fp = fopen(sigwork,READ_TEXT)) != NULLFILE){
  1194.           while(fgets(sigwork,LINELEN,fp) != NULLCHAR)
  1195.             fputs(sigwork,m->tfile);
  1196.           fclose(fp);
  1197.          }
  1198.     }
  1199.  
  1200.     if((host = strrchr(m->to,'@')) == NULLCHAR) {
  1201.         host = Hostname;        /* use our hostname */
  1202.         if(m->origto != NULLCHAR) {
  1203.             /* rewrite_address() will be called again by our
  1204.              * SMTP server, so revert to the original address.
  1205.              */
  1206.             xfree(m->to);
  1207.             m->to = m->origto;
  1208.             m->origto = NULLCHAR;
  1209.         }
  1210.     }
  1211.     else
  1212.         host++; /* use the host part of address */
  1213.  
  1214.     /* make up full from name for work file */
  1215.     if(m->tofrom != NULLCHAR)
  1216.         sprintf(fullfrom,"%s%%%s.bbs@%s",m->tofrom, m->name, Hostname);
  1217.     else
  1218.         sprintf(fullfrom,"%s@%s",m->name,Hostname);
  1219.     if(cclist != NULLLIST && stricmp(host,Hostname) != 0) {
  1220.         fseek(m->tfile,0L,0);   /* reset to beginning */
  1221.         fail = queuejob(m->tfile,Hostname,cclist,fullfrom);
  1222.         del_list(cclist);
  1223.         cclist = NULLLIST;
  1224.     }
  1225.     addlist(&cclist,m->to,0);
  1226.     fseek(m->tfile,0L,0);
  1227.     fail += queuejob(m->tfile,host,cclist,fullfrom);
  1228.     del_list(cclist);
  1229.     fclose(m->tfile);
  1230.     if(fail)
  1231.         usputs(m->user,(m->sid & MBX_SID) ?
  1232.             "*** NO\n" : "%sCouldn't queue message for delivery\n");
  1233.     else
  1234.         if(m->tomsgid != NULLCHAR &&
  1235.           (fp = fopen(Historyfile,APPEND_TEXT)) != NULLFILE) {
  1236.             fprintf(fp,"%s\n",m->tomsgid); /* Save BID in history file */
  1237.             fclose(fp);
  1238.         }
  1239.     if(m->sid & MBX_SID)
  1240.         smtptick(NULL);         /* wake SMTP to send that mail */
  1241.     return 0;
  1242. }
  1243.  
  1244. static int
  1245. dosid(argc,argv,p)
  1246. int argc;
  1247. char *argv[];
  1248. void *p;
  1249. {
  1250.     struct mbx *m = (struct mbx *)p;
  1251.     char *sid_features;
  1252.  
  1253.     if(argc == 1)
  1254.         return 1;
  1255.  
  1256.     if(argv[1][strlen(argv[1]) - 1] != ']') /* must be an SID */
  1257.         return 1;
  1258.  
  1259.     m->sid = MBX_SID;
  1260.     /* Now check to see if this is an RLI board.
  1261.      * As usual, Hank does it a bit differently from
  1262.      * the rest of the world.
  1263.      */
  1264.     if(m->stype == 'R' && strncmp(argv[1],"li",2) == 0)/* [RLI] at a minimum */
  1265.         m->sid |= MBX_RLI_SID;
  1266.     /* Check to see if the BBS supports a kludge called "hierarchical
  1267.      * routing designators."
  1268.      */
  1269.     sid_features = strrchr(argv[1],'-');
  1270.  
  1271.     if((sid_features != NULLCHAR) &&
  1272.         (strlen(sid_features) > 3) &&
  1273.         (strchr(sid_features,'h') != NULLCHAR) &&
  1274.         (strchr(sid_features,'$') != NULLCHAR))
  1275. /*
  1276.     if(strlen(argv[1]) > 2 && strcmp(argv[1]+strlen(argv[1])-3,"h$]") == 0)
  1277. */
  1278.         m->sid |= MBX_HIER_SID;
  1279.     return 0;
  1280. }
  1281.  
  1282. #ifdef XXX
  1283. /* Show non-private routes only */
  1284. int
  1285. dombiproute(argc,argv,p)
  1286. int argc;
  1287. char *argv[];
  1288. void *p;
  1289. {
  1290.     int i,bits;
  1291.     struct route *rp;
  1292.     struct mbx *m = (struct mbx *)p;
  1293.     char buf[85];
  1294.   
  1295.     if(m->privs & NO_LISTS) {
  1296.     tputs(Noperm);
  1297.     return 0;
  1298.     }
  1299.   
  1300.     tputs(RouteHeader);
  1301.     for(bits = 31; bits >= 0; bits--) {
  1302.         for(i = 0; i < HASHMOD; i++) {
  1303.             for(rp = Routes[bits][i];rp != NULLROUTE;rp = rp->next){
  1304.                 if(dumproute(rp,buf) == EOF)
  1305.                     return 0;
  1306.   
  1307.         }
  1308.         }
  1309.     }
  1310.     if(R_default.iface != NULLIF)
  1311.     dumproute(&R_default,buf);
  1312.     return 0;
  1313. }
  1314. #endif
  1315.  
  1316. #ifdef AX25
  1317. static int
  1318. dombroute(argc,argv,p)
  1319. int argc;
  1320. char *argv[];
  1321. void *p;
  1322. {
  1323.     struct axroute_tab *rp;
  1324.     int i, k;
  1325.     char tmp[11];
  1326.     struct ax25_addr call;
  1327.  
  1328.     struct mbx *m = (struct mbx *)p;
  1329.  
  1330.     if( argc < 2) {
  1331.         usputs(m->user,"Destinations:\n");
  1332.  
  1333.         for(i = 0, k = 0; i < AXROUTESIZE; i++) {
  1334.             for (rp = axroute_tab[i]; rp; rp = rp->next) {
  1335.                 pax25(tmp,(char *) &rp->call);
  1336.                 if(strlen(tmp) > 1) {
  1337.                     usprintf(m->user,"%-11.11s%s",tmp,(k == 6) ? "\n" : "");
  1338.                     k = (k+1) % 7;
  1339.                 }
  1340.             }
  1341.         }
  1342.         if (i)
  1343.             usputs(m->user,"\n");
  1344.         return 0;
  1345.     }
  1346.     for (i = 1; i < argc; i++)
  1347.         if (setcall((char *) &call,argv[i]) || (rp = axroute_tabptr(&call,0)) == 0)
  1348.             usprintf(m->user,"No route to %s\n",pax25(tmp,(char *) &call));
  1349.     else {
  1350.         tputs(" Date    GMT  Interface      Path\n");
  1351.             doroutelistentry(rp);
  1352.     }
  1353.     return 0;
  1354. }
  1355. #endif
  1356.  
  1357. static int
  1358. dombstat(argc,argv,p)
  1359. int argc;
  1360. char *argv[];
  1361. void *p;
  1362. {
  1363.     dostatus(9,0,p);
  1364.     return;
  1365. }
  1366.  
  1367. static int
  1368. dombescape(argc,argv,p)
  1369. int argc;
  1370. char *argv[];
  1371. void *p;
  1372. {
  1373.     struct mbx *m = (struct mbx *)p;
  1374.  
  1375.     if(argc < 2){
  1376.         usputs(m->user,"The escape character is: ");
  1377.         if(m->escape < 32)
  1378.             usprintf(m->user,"CTRL-%c\n",m->escape+'A'-1);
  1379.         else
  1380.             usprintf(m->user,"'%c'\n",m->escape);
  1381.         return 0;
  1382.     }
  1383.     if(strlen(argv[1]) > 1)
  1384.         if(isdigit(*argv[1]))
  1385.             m->escape = (char) atoi(argv[1]);
  1386.         else
  1387.             return 1;
  1388.     else
  1389.         m->escape = *argv[1];
  1390.     return 0;
  1391. }
  1392.  
  1393. static int
  1394. dodownload(argc,argv,p)
  1395. int argc;
  1396. char *argv[];
  1397. void *p;
  1398. {
  1399.     FILE *fp;
  1400.     struct mbx *m = (struct mbx *)p;
  1401.     char *file = pathname(m->path,argv[1]);
  1402.  
  1403.     if(!permcheck(m->path,m->privs,RETR_CMD,file)) {
  1404.         xfree(file);
  1405.         return -3;
  1406.     } else {
  1407.         if((fp = open_file(file,READ_TEXT,m->user,0)) != NULLFILE) {
  1408.             logmb(m->user,"download %c %s",m->stype,file);
  1409.             if(m->stype == 'U'){                    /* uuencode ? */
  1410.                 fclose(fp);
  1411.                 fp = fopen(file,READ_BINARY);   /* assume non-ascii */
  1412.                 uuencode(fp,m->user,argv[1]);
  1413.             } else
  1414.                 sendfile(fp,m->user,ASCII_TYPE,0);
  1415.             fclose(fp);
  1416.         }
  1417.     }
  1418.     xfree(file);
  1419.     return 0;
  1420. }
  1421.  
  1422. static int
  1423. dombuser(argc,argv,p)
  1424. int argc;
  1425. char *argv[];
  1426. void *p;
  1427. {
  1428.     int i, len, s;
  1429.     char *cp, *cp1, fsocket[MAXSOCKSIZE], upl[40], down[40];
  1430.     struct usock *up, *up1;
  1431.  
  1432. #ifdef AX25
  1433.     char tmp[AXBUF];
  1434. #endif
  1435.  
  1436. #ifdef NETROM
  1437.     struct nrroute_tab *np;
  1438.     char temp[AXBUF], *cp2, *cp3;
  1439.     char circuit[] = "Circuit (%s%s %s)";
  1440. #endif
  1441.  
  1442.     struct mbx *m = (struct mbx *) p;
  1443.  
  1444.     tprintf("%sUser:\n",(m->family == AF_NETROM) ? mbnrid : "");
  1445.  
  1446.     for(i = 0; i < NUMMBX; i++) {
  1447.         if((m = Mbox[i]) != NULLMBX){
  1448.             len = MAXSOCKSIZE;
  1449.             getpeername(m->user,fsocket,&len);
  1450.             cp = strxdup(psocket(fsocket));
  1451.  
  1452.             upl[0] = '\0';
  1453.             down[0] = '\0';
  1454.  
  1455.             switch(m->family) {             /* UPLINK */
  1456. #ifdef AX25
  1457.             case AF_AX25:
  1458.                 if((cp1 = strchr(cp,' ')) != NULLCHAR)
  1459.                     *cp1 = '\0';
  1460.                 sprintf(upl,"Uplink (%s)",cp);
  1461.                 break;
  1462. #endif
  1463. #ifdef NETROM
  1464.             case AF_NETROM:
  1465.                 if((cp1 = strchr(cp,' ')) != NULLCHAR)
  1466.                     *cp1 = '\0';
  1467.                 cp1 += 3;
  1468.                 setcall(temp,cp1);
  1469.                 if((np = find_nrroute(temp)) != NULLNRRTAB)
  1470.                     cp2 = strxdup(np->alias);
  1471.                 else
  1472.                     cp2 = "";
  1473.                 if((cp3 = strchr(cp2,' ')) != NULLCHAR)
  1474.                     *cp3 = '\0';
  1475.                 if(isalnum(*cp2))
  1476.                     strcat(cp2,":");
  1477.                 else
  1478.                     *cp2 = '\0';
  1479.                 sprintf(upl,circuit,cp2,cp1,cp);
  1480.                 xfree(cp2);
  1481.                 break;
  1482. #endif
  1483.             case AF_INET:
  1484.                 if((cp1 = strchr(cp,':')) != NULLCHAR)
  1485.                     *cp1 = '\0';
  1486.                 sprintf(upl,"Telnet (%s)",cp);
  1487.                 break;
  1488.             default:
  1489.                 strcpy(upl,"Connect");
  1490.                 break;
  1491.             }
  1492.             xfree(cp);
  1493.             tprintf("%-36s",upl);
  1494.  
  1495.             for(s = SOCKBASE; s < Nusock + SOCKBASE; s++) {
  1496.                 if((up = itop(s)) == NULLUSOCK || s == m->user)
  1497.                     continue;
  1498.                 up1 = itop(m->user);
  1499.                 if(up->owner == up1->owner) {
  1500.                     getpeername(s,fsocket,&len);
  1501.                     cp = strxdup(psocket(fsocket));
  1502.                     switch(up->type) {
  1503.                         case TYPE_TCP:
  1504.                             if((cp1 = strchr(cp,':')) != NULLCHAR)
  1505.                                 *cp1 = '\0';
  1506.                             sprintf(down,"Telnet (%s)",cp);
  1507.                             break;
  1508. #ifdef AX25
  1509.                         case TYPE_AX25I:
  1510.                             if((cp1 = strchr(cp,' ')) != NULLCHAR)
  1511.                                 *cp1 = '\0';
  1512.                             sprintf(down,"Downlink (%s %s)",
  1513.                                 pax25(tmp,m->nodename),cp);
  1514.                             break;
  1515. #endif
  1516. #ifdef NETROM
  1517.                         case TYPE_NETROML4:
  1518.                             if((cp1 = strchr(cp,' ')) != NULLCHAR)
  1519.                                 *cp1 = '\0';
  1520.                             cp1 += 3;
  1521.                             setcall(temp,cp1);
  1522.                             np = find_nrroute(temp);
  1523.                             cp2 = strxdup(np->alias);
  1524.                             if((cp3 = strchr(cp2,' ')) != NULLCHAR)
  1525.                                 *cp3 = '\0';
  1526.                             addrcp(cp,m->nodename);
  1527.                             cp[ALEN] ^= 0x1e;
  1528.                             if(isalnum(*cp2))
  1529.                                 strcat(cp2,":");
  1530.                             else
  1531.                                 *cp2 = '\0';
  1532.                             sprintf(down,circuit,cp2,cp1,pax25(temp,cp));
  1533.                             xfree(cp2);
  1534.                             break;
  1535. #endif
  1536.                         default:
  1537.                             strcpy(down,"Connect");
  1538.                             break;
  1539.                     }
  1540.                     xfree(cp);
  1541.                     tprintf("<-->  %s",down);
  1542.                     break;
  1543.                 }
  1544.             }
  1545.         tputs("\n");
  1546.         }
  1547.     }
  1548.     return 0;
  1549. }
  1550.  
  1551. static int
  1552. dombupload(argc,argv,p)
  1553. int argc;
  1554. char *argv[];
  1555. void *p;
  1556. {
  1557.     FILE *fp;
  1558.     char buf[LINELEN];
  1559.     struct mbx *m = (struct mbx *)p;
  1560.     char *file = pathname(m->path,argv[1]);
  1561.  
  1562.     if(!permcheck(m->path,m->privs,STOR_CMD,file)) {
  1563.         xfree(file);
  1564.         return -3;
  1565.     }
  1566.     if((fp = open_file(file,WRITE_TEXT,m->user,1)) == NULLFILE) {
  1567.         xfree(file);
  1568.         return 0;
  1569.     }
  1570.     usprintf(m->user,"Send file. %s",Howtoend);
  1571.     logmb(m->user,"upload %s",file);
  1572.     for(;;){
  1573.         if(mbxrecvline(m->user,buf,LINELEN,-1) == -1){
  1574.             unlink(file);
  1575.             break;
  1576.         }
  1577.         if(buf[0] == 0x01){  /* CTRL-A */
  1578.             unlink(file);
  1579.             usputs(m->user,Aborted);
  1580.             break;
  1581.         }
  1582.         if(buf[0] == CTLZ
  1583.           || !stricmp(buf,"/ex")
  1584.           || !stricmp(buf,"***end")
  1585.           || !stricmp(buf,"."))
  1586.             break;
  1587.         fputs(buf,fp);
  1588.  
  1589. #if !defined(UNIX) && !defined(__TURBOC__) && !defined(AMIGA)
  1590.         /* Needed only if the OS uses a CR/LF
  1591.          * convention oand putc doesn't do
  1592.          * an automatic translation
  1593.          */
  1594.         if(putc('\r',fp) == EOF)
  1595.             break;
  1596. #endif
  1597.         if(putc('\n',fp) == EOF)
  1598.             break;
  1599.     }
  1600.     fclose(fp);
  1601.     return 0;
  1602. }
  1603.  
  1604. static int
  1605. dowhat(argc,argv,p)
  1606. int argc;
  1607. char *argv[];
  1608. void *p;
  1609. {
  1610.     FILE *fp;
  1611.     char *file;
  1612.  
  1613.     struct mbx *m = (struct mbx *)p;
  1614.  
  1615.     if(m->security)
  1616.         return 0;
  1617.  
  1618.     if(argc < 2)
  1619.         file = strxdup(m->path);
  1620.     else
  1621.         file = pathname(m->path,argv[1]);
  1622.  
  1623.     if(!permcheck(m->path,m->privs,RETR_CMD,file)) {
  1624.         xfree(file);
  1625.         return -3;
  1626.     }
  1627.  
  1628.     if((fp = dir(file,1)) != NULLFILE)
  1629.         sendfile(fp,m->user,ASCII_TYPE,0);
  1630.     fclose(fp);
  1631.     xfree(file);
  1632.     return 0;
  1633. }
  1634.  
  1635. int
  1636. dosysopset(argc,argv,p)
  1637. int argc;
  1638. char *argv[];
  1639. void *p;
  1640. {
  1641.     if(strlen(argv[1]) == 5 && atol(argv[1]) != 0)
  1642.         strcpy(number,argv[1]);
  1643.     return 0;
  1644. }
  1645. int
  1646. dormncsys(argc,argv,p)
  1647. int argc;
  1648. char *argv[];
  1649. void *p;
  1650. {
  1651.     long org;
  1652.  
  1653.     long n1, n2, x;
  1654.     int i;
  1655.  
  1656.     org=atol(number);    // eigene Nr
  1657.  
  1658.     n1 = atol(argv[1]);  // Fremde Nr
  1659.      if (argc < 3)
  1660.       n2 = org;
  1661.      else
  1662.       n2 = atol(argv[2]);
  1663.  
  1664.     for (i = 0, x = 0; i < 5; i++) {
  1665.       x += (n1 % 10) * (n2 % 10);
  1666.       n1 /= 10;
  1667.       n2 /= 10;
  1668.     }
  1669.  
  1670.     printf("%d\n",x);
  1671. return 0;
  1672.  
  1673. }
  1674.  
  1675.  
  1676.  
  1677. static int
  1678. dosysop(argc,argv,p)
  1679. int argc;
  1680. char *argv[];
  1681. void *p;
  1682. {
  1683.     int c, i, k;
  1684.     unsigned long int digit1[25], digit;
  1685.     extern struct cmds Cmds[];
  1686.  
  1687.     struct mbx *m = (struct mbx *) p;
  1688.  
  1689.     logmb(m->user,"SYSOP");
  1690.     if(!(m->privs & SYSOP_CMD))
  1691.         return -3;
  1692.  
  1693.     randomize();
  1694.     for(i=0; i<15; i++)     {
  1695.         digit1[i] = random(10);
  1696.         usprintf(m->user,"%d",digit1[i]);
  1697.  
  1698.         if(i == 4 || i == 9)
  1699.             usputs(m->user,", ");
  1700.     }
  1701.     usputs(m->user,">");
  1702.  
  1703.     c = mbxrecvline(m->user,m->line,MBXLINE,m->escape);
  1704.     if(c == EOF || c == -2)
  1705.         return 0;
  1706.  
  1707.     if((digit = atol(number)) == 0)
  1708.         digit = 22222;
  1709.     digit1[15] = digit/10000;
  1710.     digit -= digit1[15]*10000;
  1711.     digit1[16] = digit/1000;
  1712.     digit -= digit1[16]*1000;
  1713.     digit1[17] = digit/100;
  1714.     digit -= digit1[17]*100;
  1715.     digit1[18] = digit/10;
  1716.     digit -= digit1[18]*10;
  1717.     digit1[19] = digit;
  1718.  
  1719.     for(i=0; i<3; i++) {
  1720.         digit1[i+20] = 0;
  1721.         for(k=0; k<5; k++)
  1722.             digit1[i+20] += digit1[k+i*5] * digit1[k+15];
  1723.     }
  1724.     rip(m->line);
  1725.  
  1726.     if((digit = atol(m->line)) != 0
  1727.       && (digit == digit1[20] || digit == digit1[21] || digit == digit1[22])) {
  1728.         for(;;) {
  1729.             usputs(m->user,"Net> ");
  1730.             c = mbxrecvline(m->user,m->line,MBXLINE,m->escape);
  1731.             if(c == EOF || c == -2)
  1732.                 break;
  1733.             cmdparse(Cmds,m->line,NULL);
  1734.         }
  1735.         return 0;
  1736.     } else
  1737.         return -3;
  1738. }
  1739.  
  1740. /* Handle the "*** Done" command when reverse forwarding ends
  1741.  */
  1742. static int
  1743. dostars(argc,argv,p)
  1744. int argc;
  1745. char *argv[];
  1746. void *p;
  1747. {
  1748.     struct mbx *m = (struct mbx *)p;
  1749.  
  1750.     if(strcmp(argv[1],"error?") == 0)
  1751.         return -2;
  1752.     if(strcmp(argv[1],"done") == 0 && (m->sid & MBX_SID))   /* "*** Done" or similar */
  1753.         return 2;
  1754.     return -1;
  1755. }
  1756.  
  1757. static int
  1758. doarea(argc,argv,p)
  1759. int argc;
  1760. char *argv[];
  1761. void *p;
  1762. {
  1763.     FILE *fp;
  1764.     char *cp, *area, Areatext[] = "Area %s: %d message%s\n";
  1765.     static char Nomail[] = "No message%s\n";
  1766.  
  1767.     struct mbx *m = (struct mbx *) p;
  1768.  
  1769.     if(argc < 2){
  1770.         area = strxdup(m->area);
  1771.         while((cp = strchr(area,'/')) != NULLCHAR)
  1772.             *cp = '.';
  1773.         usprintf(m->user,"Current area: %s\nAvailable areas:\n",area);
  1774.         xfree(area);
  1775.         usprintf(m->user,"%-15s  Your private mail area\n",m->name);
  1776.         if((fp = fopen(Arealist,READ_TEXT)) != NULLFILE) {
  1777.             sendfile(fp,m->user,ASCII_TYPE,0);
  1778.             fclose(fp);
  1779.             usputs(m->user,"\n");
  1780.         }
  1781.         return 0;
  1782.     }
  1783.     if((m->privs & SYSOP_CMD) || strcmp(m->name,argv[1]) == 0){
  1784.         changearea(m,argv[1]);
  1785.         if(!strcmp(m->name,m->area)) {
  1786.             if(m->nmsgs) {
  1787.                 usprintf(m->user,"You have %d message%s",
  1788.                     m->nmsgs,m->nmsgs == 1 ? "" : "s");
  1789.                 if(m->newmsgs)
  1790.                     usprintf(m->user," - %d new",m->newmsgs);
  1791.                 usputs(m->user,"\n\n");
  1792.             } else {
  1793.                 m->narea[0] = '\0';
  1794.             }
  1795.         } else {
  1796.             area = strxdup(m->area);
  1797.             while((cp = strchr(area,'/')) != NULLCHAR)
  1798.                 *cp = '.';
  1799.             usprintf(m->user,Areatext,area,m->nmsgs,m->nmsgs == 1 ? "" : "s");
  1800.             xfree(area);
  1801.         }
  1802.         return 0;
  1803.     }
  1804.     if(isarea(argv[1])) {
  1805.         changearea(m,argv[1]);
  1806.         area = strxdup(m->area);
  1807.         while((cp = strchr(area,'/')) != NULLCHAR)
  1808.             *cp = '.';
  1809.         if(m->nmsgs)
  1810.             usprintf(m->user,Areatext,area,m->nmsgs,m->nmsgs == 1 ? "" : "s");
  1811.         else
  1812.             usprintf(m->user,Nomail,"s");
  1813.         xfree(area);
  1814.     }
  1815.     else
  1816.         usprintf(m->user,"No such area: %s\n",argv[1]);
  1817.     return 0;
  1818. }
  1819.  
  1820. /* subroutine to do the actual switch from one area to another */
  1821. void
  1822. changearea(m,area)
  1823. struct mbx *m;
  1824. char *area;
  1825. {
  1826.     char *cp;
  1827.  
  1828.     semwait(&Areawait,1);
  1829.     closenotes(m);
  1830.     m->nmsgs = m->newmsgs = m->current = 0;
  1831.     strcpy(m->area,area);
  1832. #ifdef MSDOS
  1833.     while((cp = strchr(m->area,'\\')) != NULLCHAR)
  1834.         *cp = '/';
  1835. #endif
  1836.     strcpy(m->narea,m->area);
  1837.     if((cp = strpbrk(m->narea," -/.:")) != NULLCHAR)
  1838.         *cp = '\0';
  1839.     strupr(m->narea);
  1840.     scanmail(m);
  1841.     semrel(&Areawait);
  1842. }
  1843.  
  1844. #ifdef AX25
  1845. static int
  1846. dogateway(argc,argv,p)
  1847. int argc;
  1848. char *argv[];
  1849. void *p;
  1850. {
  1851.     struct mbx *m = (struct mbx *)p;
  1852.     struct sockaddr_ax fsocket, lsocket;
  1853.     int s;
  1854.     char *ap, path[10*AXALEN+1];
  1855.     struct iface *ifp = NULLIF;
  1856.     struct ax25_cb axp;
  1857.  
  1858.     if(argc < 2) {
  1859.         if(MAttended){
  1860.             char buf[5], *newargv[3];
  1861.  
  1862.             newargv[0] = "telnet";
  1863.             newargv[1] = (MHostname != NULLCHAR) ? MHostname : Hostname;
  1864.             sprintf(buf,"%d",IPPORT_TTYLINK);
  1865.             newargv[2] = buf;
  1866.             return dombtelnet(3,newargv,p);
  1867.         } else {
  1868.             char *name = strxdup(MBHostname);
  1869.             strlwr(name);
  1870.             usprintf(m->user,"OP is absent, pse leave msg with \"s %s\"\n",name);
  1871.             xfree(name);
  1872.             return 0;
  1873.         }
  1874.     }
  1875.  
  1876.     if(!(m->privs & AX25_CMD))
  1877.         return -3;
  1878.  
  1879.   argc--;
  1880.   argv++;
  1881.  
  1882.   if((ifp = if_lookup(*argv)) != NULLIF) {
  1883.     if(ifp->output != ax_output) {
  1884.         usprintf(m->user,Badax,*argv);
  1885.         return 0;
  1886.     }
  1887.     argc--;
  1888.     argv++;
  1889.   }
  1890.   for (ap = path; argc > 0; argc--, argv++) {
  1891.     if (!strncmp("via", *argv, strlen(*argv))) continue;
  1892.     if (ap > path + sizeof(path) - 1) {
  1893.       usputs(m->user,"Max 8 digis\n");
  1894.       return 0;
  1895.     }
  1896.     if (setcall(ap, *argv)) {
  1897.       usprintf(m->user,"Invalid call %s\n", *argv);
  1898.       return 0;
  1899.     }
  1900.     ap[ALEN] &= ~E;
  1901.  
  1902.     if (ap == path) {
  1903.       ap += AXALEN;
  1904.       addrcp(ap,Mycall);
  1905.       ap[ALEN] &= ~E;
  1906.     }
  1907.     ap += AXALEN;
  1908.   }
  1909.   if (ap < path + 2 * AXALEN) {
  1910.     usputs(m->user,"Missing call\n");
  1911.     return 0;
  1912.   }
  1913.   ap[-1] |= E;
  1914.  
  1915.   memset(&axp,0,sizeof(struct ax25_cb));
  1916.  
  1917.   build_path(&axp,ifp,path,0,0);
  1918.  
  1919.   if(!axp.iface) {
  1920.     usputs(m->user,"No specified iface\n");
  1921.     return 0;
  1922.   }
  1923.  
  1924.   addrcp(axp.path + AXALEN,axp.iface->hwaddr);
  1925.   axroute_add(&axp,0);
  1926.  
  1927.   if((s = socket(AF_AX25,SOCK_STREAM,0)) == -1){
  1928.     usputs(m->user,Nosocket);
  1929.     return 0;
  1930.   }
  1931.  
  1932.   fsocket.sax_family = AF_AX25;
  1933.   addrcp(fsocket.ax25_addr,axp.path);
  1934.   memcpy(fsocket.iface,axp.iface->name,ILEN);
  1935.   m->startmsg = NULLCHAR;
  1936.  
  1937.   lsocket.sax_family = AF_AX25;
  1938.   addrcp(lsocket.ax25_addr,(*m->name == '\0') ?
  1939.     axp.iface->hwaddr : m->nodename);
  1940.   bind(s,(char *)&lsocket,sizeof(struct sockaddr_ax));
  1941.   return gw_connect(m,s,(char *)&fsocket, sizeof(struct sockaddr_ax));
  1942. }
  1943. #else
  1944. static int
  1945. dogateway(argc,argv,p)
  1946. int argc;
  1947. char *argv[];
  1948. void *p;
  1949. {
  1950.     if(argc < 2) {
  1951.         if(MAttended){
  1952.             char buf[5], *newargv[3];
  1953.  
  1954.             newargv[0] = "telnet";
  1955.             newargv[1] = Hostname;
  1956.             sprintf(buf,"%d",IPPORT_TTYLINK);
  1957.             newargv[2] = buf;
  1958.             return dombtelnet(3,newargv,p);
  1959.         } else {
  1960.             char *name;
  1961.  
  1962.             name = strxdup(MBHostname);
  1963.             strlwr(name);
  1964.             usprintf(m->user,"OP is absent, pse leave msg with \"s %s\"\n",name);
  1965.             xfree(name);
  1966.             return 0;
  1967.         }
  1968.     }
  1969.  
  1970.     usputs(m->user,Noserv);
  1971.     return 0;
  1972. }
  1973. #endif
  1974.  
  1975. static int
  1976. dombtelnet(argc,argv,p)
  1977. int argc;
  1978. char *argv[];
  1979. void *p;
  1980. {
  1981.     int s, len, i;
  1982.     char dsocket[MAXSOCKSIZE];
  1983.     struct sockaddr_in fsocket;
  1984.  
  1985.     struct mbx *m = (struct mbx *) p;
  1986.  
  1987.     fsocket.sin_family = AF_INET;
  1988.     fsocket.sin_port = (argc < 3) ? IPPORT_TELNET : atoi(argv[2]);
  1989.  
  1990.     if((fsocket.sin_addr.s_addr = resolve(argv[1])) == 0){
  1991.         usprintf(m->user,Badhost,argv[1]);
  1992.         return 0;
  1993.     }
  1994.     /* Only local telnets are are allowed to the unprivileged user */
  1995.     if(!(m->privs & TELNET_CMD) && !ismyaddr(fsocket.sin_addr.s_addr))
  1996.         return -3;
  1997.  
  1998.     if((s = socket(AF_INET,SOCK_STREAM,0)) == -1){
  1999.         usputs(m->user,Nosocket);
  2000.         return 0;
  2001.     }
  2002.     switch(fsocket.sin_port) {
  2003.     case IPPORT_TTYLINK:
  2004.         m->startmsg = mxallocw(80);
  2005.         len = MAXSOCKSIZE;
  2006.         i = getpeername(m->user,dsocket,&len);
  2007.         sprintf(m->startmsg,"*** Incoming call from %s@%s ***\n",
  2008.             m->name,(i != -1) ? psocket(dsocket): Hostname);
  2009.         break;
  2010. #ifdef CONVERS
  2011.     case IPPORT_CONVERS:
  2012.         if(m->startmsg == NULLCHAR) {
  2013.             m->startmsg = mxallocw(40);
  2014.             sprintf(m->startmsg,
  2015.                 "/n %s %d\n",m->name,(argc > 3) ? atoi(argv[3]) : 0);
  2016.         }
  2017.         m->state = MBX_CONVERS;
  2018.         break;
  2019. #endif
  2020.     }
  2021.     return gw_connect(m,s,(char *)&fsocket,SOCKSIZE);
  2022. }
  2023.  
  2024. static int
  2025. dombfinger(argc,argv,p)
  2026. int argc;
  2027. char *argv[];
  2028. void *p;
  2029. {
  2030.     struct mbx *m = (struct mbx *)p;
  2031.     char *host, *user = NULLCHAR, buf[8], *newargv[3];
  2032.  
  2033.     if(argc > 2){
  2034.         usputs(m->user,"Usage: finger <user[@host]|@host>\n");
  2035.         return 0;
  2036.     }
  2037.     host = Hostname;
  2038.     if(argc == 2){
  2039.         if((host = strchr(argv[1], '@')) != NULLCHAR){
  2040.             *host = '\0';
  2041.             host++;
  2042.         } else
  2043.             host = Hostname;
  2044.         user = argv[1];
  2045.     }
  2046.     m->startmsg = mxallocw(80);
  2047.     sprintf(m->startmsg,"%s\n",(user != NULLCHAR) ? user : "");
  2048.     newargv[0] = "telnet";
  2049.     newargv[1] = host;
  2050.     sprintf(buf,"%d",IPPORT_FINGER);
  2051.     newargv[2] = buf;
  2052.     return dombtelnet(3,newargv,p);
  2053. }
  2054.  
  2055. #ifdef CONVERS
  2056. static int
  2057. dombconvers(argc,argv,p)
  2058. int argc;
  2059. char *argv[];
  2060. void *p;
  2061. {
  2062.     char buf[8], *newargv[3];
  2063.  
  2064.     struct mbx *m = (struct mbx *) p;
  2065.  
  2066.     m->startmsg = mxallocw(40);
  2067.     sprintf(m->startmsg,"/n %s %s\n",m->name,(argc > 1) ? argv[1] : "0");
  2068.     newargv[0] = "telnet";
  2069.     newargv[1] = Hostname;
  2070.     sprintf(buf,"%d",IPPORT_CONVERS);
  2071.     newargv[2] = buf;
  2072.     return dombtelnet(3,newargv,p);
  2073. }
  2074. #endif
  2075.  
  2076. /* Generic mbox gateway code. It sends and frees the contents of m->startmsg
  2077.  * when the connection has been established unless it a null pointer.
  2078.  */
  2079. static int near
  2080. gw_connect(m,s,fsocket,len)
  2081. struct mbx *m;
  2082. int s;
  2083. char *fsocket;
  2084. int len;
  2085. {
  2086.     int c;
  2087.     char *cp, *cp1, *node, buf[80];
  2088.     struct proc *child;
  2089.     struct gwalarm *gwa;
  2090.  
  2091.     sockmode(s,SOCK_ASCII);
  2092.     child = newproc("gw supervisor",256,gw_superv,0,Curproc,m,0);
  2093.     if(m->family == AF_AX25) {
  2094.         usputs(m->user,"link setup...\n");
  2095.         usflush(m->user);
  2096.     }
  2097.     node = strxdup(psocket((struct sockaddr *)fsocket));
  2098.     if((cp1 = strchr(node,' ')) != NULLCHAR)
  2099.         *cp1 = '\0';
  2100.  
  2101.     if(connect(s,fsocket,len) == -1){
  2102.         if((cp = sockerr(s)) != NULLCHAR) {
  2103.             switch(cp[0]) {
  2104.             case 'R':
  2105.                 sprintf(buf,"%susy from",
  2106.                     (m->family == AF_NETROM)?"B":"*** b");
  2107.                 break;
  2108.             case 'T':
  2109.                 if(m->family != AF_NETROM) {
  2110.                     sprintf(buf,"*** timeout with");
  2111.                     break;
  2112.                 }
  2113.             default:
  2114.                 sprintf(buf,"%sailure with",
  2115.                     (m->family == AF_NETROM)?"F":"*** f");
  2116.                 break;
  2117.             }
  2118.             usprintf(m->user,"%s%s %s\n",
  2119.                 (m->family == AF_NETROM) ? mbnrid : "",buf,node);
  2120.         }
  2121.         xfree(m->startmsg);
  2122.         m->startmsg = NULLCHAR;
  2123.         xfree(node);
  2124.         killproc(child);
  2125.         close_s(s);
  2126.         return 0;
  2127.     }
  2128.     logmb(Curproc->input,"connect %s",node);
  2129.     usprintf(m->user,"%s%sonnected to %s\n",
  2130.         (m->family == AF_NETROM) ? mbnrid : "",
  2131.         (m->family == AF_NETROM) ? "C" : "*** c",
  2132.         node);
  2133.     xfree(node);
  2134.     /* The user did not type the escape character */
  2135.     killproc(child);
  2136.  
  2137.     if(m->startmsg != NULLCHAR){
  2138.         usputs(s,m->startmsg);
  2139.         xfree(m->startmsg);
  2140.         m->startmsg = NULLCHAR;
  2141.     }
  2142.  
  2143.     /* Since NOS does not flush the output socket after a certain
  2144.      * period of time, we have to arrange that ourselves.
  2145.      */
  2146.     gwa = (struct gwalarm *)mxallocw(sizeof(struct gwalarm));
  2147.     stop_timer(&gwa->t);
  2148.     gwa->s1 = Curproc->output;
  2149.     gwa->s2 = s;
  2150.     gwa->t.func = gw_alarm;
  2151.     gwa->t.arg = (void *) gwa;
  2152.     set_timer(&gwa->t,240);                 /* DB3FL */
  2153.     start_timer(&gwa->t);
  2154.     /* Fork off the receive process */
  2155.     child = newproc("gw in",1024,gw_input,s,m,Curproc,0);
  2156.  
  2157.     for(;;){
  2158.         if((c = recvchar(Curproc->input)) == EOF)
  2159.             break;
  2160.         if(c == m->escape){
  2161.             if(socklen(Curproc->input,0))
  2162.                 recv_mbuf(Curproc->input,NULL,0,NULLCHAR,0);
  2163.             break;
  2164.         }
  2165.         if(usputc(s,c) == EOF)
  2166.             break;
  2167.     }
  2168.     stop_timer(&gwa->t);
  2169.     xfree((char *)gwa);
  2170.     close_s(s);
  2171.     killproc(child); /* get rid of the receive process */
  2172.     if(m->family == AF_INET || m->family == AF_LOCAL)
  2173.         usprintf(m->user,"%c%c%c\n",IAC,WONT,TN_ECHO);
  2174.     return 0;
  2175. }
  2176.  
  2177. static void
  2178. gw_input(s,notused,p)
  2179. int s;
  2180. void *notused;
  2181. void *p;
  2182. {
  2183.     int c;
  2184.     char *cp;
  2185.  
  2186.     struct proc *parent = (struct proc *) p;
  2187.     struct mbx *m = (struct mbx *) notused;
  2188.  
  2189.     while((c = recvchar(s)) != EOF)
  2190.         tputc(c);
  2191.     if((cp = sockerr(s)) != NULLCHAR && m->family != AF_NETROM) {
  2192.         switch(*cp) {
  2193.         case 'T':
  2194.             usprintf(m->user,"\n*** %s: Link failure",MBHostname);
  2195.             break;
  2196.         case 'R':
  2197.             usputs(m->user,"*** DM received");
  2198.             break;
  2199.         }
  2200.     }
  2201.     usprintf(m->user,"\n%s%seconnected to %s\n",
  2202.         (m->family == AF_NETROM) ? mbnrid : "",
  2203.         (m->family == AF_NETROM) ? "R" : "*** r",
  2204.         MBHostname);
  2205.  
  2206.     /* Tell the parent that we are no longer connected */
  2207.     alert(parent,(void *)ENOTCONN);
  2208.     pwait(Curproc); /* Now wait to be killed */
  2209. }
  2210.  
  2211. /* Check if the escape character is typed while the parent process is busy
  2212.  * doing other things.
  2213.  */
  2214. static void
  2215. gw_superv(null,proc,p)
  2216. int null;
  2217. void *proc;
  2218. void *p;
  2219. {
  2220.     int c;
  2221.     struct proc *parent = (struct proc *) proc;
  2222.     struct mbx *m = (struct mbx *) p;
  2223.  
  2224.     while((c = recvchar(Curproc->input)) != EOF)
  2225.         if(c == m->escape){
  2226.             /* flush anything in the input queue */
  2227.             if(socklen(Curproc->input,0))
  2228.                 recv_mbuf(Curproc->input,NULL,0,NULLCHAR,0);
  2229.             break;
  2230.         }
  2231.     alert(parent,(void *)EINTR);    /* Tell the parent to quit */
  2232.     pwait(Curproc);                 /* Please kill me */
  2233. }
  2234.  
  2235. static void
  2236. gw_alarm(p)
  2237. void *p;
  2238. {
  2239.     struct gwalarm *gwa = (struct gwalarm *)p;
  2240.     char oldbl;
  2241.     struct usock *up;
  2242.  
  2243.     /* Flush sockets s1 and s2, but first make sure that the socket
  2244.      * is set to non-blocking mode, to prevent the flush from blocking
  2245.      * if the high water mark has been reached.
  2246.      */
  2247.     if((up = itop(gwa->s1)) != NULLUSOCK) {
  2248.         oldbl = up->noblock;
  2249.         up->noblock = 1;
  2250.         usflush(gwa->s1);
  2251.         up->noblock = oldbl;
  2252.     }
  2253.     if((up = itop(gwa->s2)) != NULLUSOCK) {
  2254.         oldbl = up->noblock;
  2255.         up->noblock = 1;
  2256.         usflush(gwa->s2);
  2257.         up->noblock = oldbl;
  2258.     }
  2259.     start_timer(&gwa->t);
  2260. }
  2261.  
  2262. #ifdef AX25
  2263. static int
  2264. dombheard(argc,argv,p)
  2265. int argc;
  2266. char *argv[];
  2267. void *p;
  2268. {
  2269.     return doaxheard(argc,argv,p);
  2270. }
  2271. #endif
  2272.  
  2273. #ifdef  NETROM
  2274. static int
  2275. dombnodes(argc,argv,p)
  2276. int argc;
  2277. char *argv[];
  2278. void *p;
  2279. {
  2280.     struct mbx *m = (struct mbx *) p;
  2281.  
  2282.     if(!(m->privs & NETROM_CMD))
  2283.         return -3;
  2284.  
  2285.     if(Nrifaces[0].alias == NULLCHAR) {
  2286.         usputs(m->user,Noserv);
  2287.         return 0;
  2288.     }
  2289.     if(argc < 2 || (argc > 1 && stricmp(argv[1],"tcp") == 0)) {
  2290.         usprintf(m->user,"%sNodes:\n",(m->family == AF_NETROM) ? mbnrid : "");
  2291.         return doroutedump(argc < 2 ? 9 : 0,0,p);
  2292.     }
  2293.     if(dorouteinfo(9,argv,p) == -1) {
  2294.         usprintf(m->user,"%s%so route to %s\n",
  2295.             (m->family == AF_NETROM) ? mbnrid : "",
  2296.             (m->family == AF_NETROM) ? "N" : "*** n",
  2297.             strupr(argv[1]));
  2298.         return -1;
  2299.     }
  2300.     return 0;
  2301. }
  2302.  
  2303. static int
  2304. dombnrconnect(argc,argv,p)
  2305. int argc;
  2306. char *argv[];
  2307. void *p;
  2308. {
  2309.     int s;
  2310.     struct sockaddr_nr lsocket, fsocket;
  2311.     char *np, alias[AXBUF];
  2312.  
  2313.     struct mbx *m = (struct mbx *) p;
  2314.  
  2315.     if((s = socket(AF_NETROM,SOCK_SEQPACKET,0)) == -1){
  2316.         usputs(m->user,Nosocket);
  2317.         return 0;
  2318.     }
  2319.     lsocket.nr_family = AF_NETROM;
  2320.  
  2321.     /* Set up our local username, bind would use Mycall instead */
  2322.     addrcp(lsocket.nr_addr.user,m->nodename);
  2323.     lsocket.nr_addr.user[ALEN] ^= 0x1e;
  2324.  
  2325.     /* Putting anything else than Mycall here will not work */
  2326.     addrcp(lsocket.nr_addr.node,Mycall);
  2327.     bind(s,(char *)&lsocket,sizeof(struct sockaddr_nr));
  2328.  
  2329.     /* See if the requested destination could be an alias, and
  2330.      * find and use it if it is.  Otherwise assume it is an ax.25
  2331.      * address.
  2332.      */
  2333.     if(putalias(alias,argv[1],0) != -1 &&
  2334.         (np = find_nralias(alias)) != NULLCHAR){
  2335.         addrcp(fsocket.nr_addr.user,np);
  2336.         addrcp(fsocket.nr_addr.node,np);
  2337.     } else {        /* parse ax25 callsign */
  2338.         /* Only the user callsign of the remote station is never used by */
  2339.         /* NET/ROM, but it is needed for the psocket() call. */
  2340.         setcall(fsocket.nr_addr.user,argv[1]);
  2341.         setcall(fsocket.nr_addr.node,argv[1]);
  2342.     }
  2343.     fsocket.nr_family = AF_NETROM;
  2344.     return gw_connect(m,s,(char *)&fsocket, sizeof(struct sockaddr_nr));
  2345. }
  2346. #endif
  2347.  
  2348. /* States for send line parser state machine */
  2349. #define         LOOK_FOR_USER           2
  2350. #define         IN_USER                         3
  2351. #define         AFTER_USER                      4
  2352. #define         LOOK_FOR_HOST           5
  2353. #define         IN_HOST                         6
  2354. #define         AFTER_HOST                      7
  2355. #define         LOOK_FOR_FROM           8
  2356. #define         IN_FROM                         9
  2357. #define         AFTER_FROM                      10
  2358. #define         LOOK_FOR_MSGID          11
  2359. #define         IN_MSGID                        12
  2360. #define         FINAL_STATE                     13
  2361. #define         ERROR_STATE                     14
  2362.  
  2363. /* Prepare the addressee.  If the address is bad, return -1, otherwise
  2364.  * return 0
  2365.  */
  2366. static int near
  2367. mbx_to(argc,argv,p)
  2368. int argc;
  2369. char *argv[];
  2370. void *p;
  2371. {
  2372.     char *cp, *user, *host, *from, *msgid;
  2373.     int state, i, userlen = 0, hostlen = 0, fromlen = 0, msgidlen = 0;
  2374.  
  2375.     struct mbx *m = (struct mbx *)p;
  2376.  
  2377.     /* Free anything that might be allocated
  2378.      * since the last call to mbx_to() or mbx_reply()
  2379.      */
  2380.     xfree(m->to);
  2381.     m->to = NULLCHAR;
  2382.     xfree(m->tofrom);
  2383.     m->tofrom = NULLCHAR;
  2384.     xfree(m->tomsgid);
  2385.     m->tomsgid = NULLCHAR;
  2386.     xfree(m->origto);
  2387.     m->origto = NULLCHAR;
  2388.  
  2389.     if(argc == 1)
  2390.         return -1;
  2391.     i = 1;
  2392.     cp = argv[i];
  2393.     state = LOOK_FOR_USER;
  2394.     while(state < FINAL_STATE){
  2395.         switch(state){
  2396.         case LOOK_FOR_USER:
  2397.             if(*cp == '@' || *cp == '<' || *cp == '$'){
  2398.                 state = ERROR_STATE;            /* no user */
  2399.             } else {
  2400.                 user = cp;                                      /* point at start */
  2401.                 userlen++;                                      /* start counting */
  2402.                 state = IN_USER;
  2403.             }
  2404.             break;
  2405.         case IN_USER:
  2406.             switch(*cp){
  2407.             case '\0':
  2408.                 state = AFTER_USER;                     /* done with username */
  2409.                 break;
  2410.             case '@':
  2411.                 state = LOOK_FOR_HOST;          /* hostname should follow */
  2412.                 break;
  2413.             case '<':
  2414.                 state = LOOK_FOR_FROM;          /* from name should follow */
  2415.                 break;
  2416.             case '$':
  2417.                 state = LOOK_FOR_MSGID;         /* message id should follow */
  2418.                 break;
  2419.             default:
  2420.                 userlen++;                                      /* part of username */
  2421.             }
  2422.             break;
  2423.         case AFTER_USER:
  2424.             switch(*cp){
  2425.             case '@':
  2426.                 state = LOOK_FOR_HOST;          /* hostname follows */
  2427.                 break;
  2428.             case '<':
  2429.                 state = LOOK_FOR_FROM;          /* fromname follows */
  2430.                 break;
  2431.             case '$':
  2432.                 state = LOOK_FOR_MSGID;         /* message id follows */
  2433.                 break;
  2434.             default:
  2435.                 state = ERROR_STATE;
  2436.             }
  2437.             break;
  2438.         case LOOK_FOR_HOST:
  2439.             if(*cp == '@' || *cp == '<' || *cp == '$'){
  2440.                 state = ERROR_STATE;
  2441.                 break;
  2442.             }
  2443.             if(*cp == '\0')
  2444.                 break;
  2445.             host = cp;
  2446.             hostlen++;
  2447.             state = IN_HOST;
  2448.             break;
  2449.         case IN_HOST:
  2450.             switch(*cp){
  2451.             case '\0':
  2452.                 state = AFTER_HOST;                     /* found user@host */
  2453.                 break;
  2454.             case '@':
  2455.                 state = ERROR_STATE;            /* user@host@? */
  2456.                 break;
  2457.             case '<':
  2458.                 state = LOOK_FOR_FROM;          /* fromname follows */
  2459.                 break;
  2460.             case '$':
  2461.                 state = LOOK_FOR_MSGID;         /* message id follows */
  2462.                 break;
  2463.             default:
  2464.                 hostlen++;
  2465.             }
  2466.             break;
  2467.         case AFTER_HOST:
  2468.             switch(*cp){
  2469.             case '@':
  2470.                 state = ERROR_STATE;            /* user@host @ */
  2471.                 break;
  2472.             case '<':
  2473.                 state = LOOK_FOR_FROM;          /* user@host < */
  2474.                 break;
  2475.             case '$':
  2476.                 state = LOOK_FOR_MSGID;         /* user@host $ */
  2477.                 break;
  2478.             default:
  2479.                 state = ERROR_STATE;            /* user@host foo */
  2480.             }
  2481.             break;
  2482.         case LOOK_FOR_FROM:
  2483.             if(*cp == '@' || *cp == '<' || *cp == '$'){
  2484.                 state = ERROR_STATE;
  2485.                 break;
  2486.             }
  2487.             if(*cp == '\0')
  2488.                 break;
  2489.             from = cp;
  2490.             fromlen++;
  2491.             state = IN_FROM;
  2492.             break;
  2493.         case IN_FROM:
  2494.             switch(*cp){
  2495.             case '\0':
  2496.                 state = AFTER_FROM;                     /* user@host <foo */
  2497.                 break;
  2498.             case '<':
  2499.                 state = ERROR_STATE;            /* user@host <foo< */
  2500.                 break;
  2501.             case '$':
  2502.                 state = LOOK_FOR_MSGID;         /* message id follows */
  2503.                 break;
  2504.             default:
  2505.                 fromlen++;
  2506.             }
  2507.             break;
  2508.         case AFTER_FROM:
  2509.             switch(*cp){
  2510.             case '@':                                               /* user@host <foo @ */
  2511.             case '<':                                               /* user@host <foo < */
  2512.                 state = ERROR_STATE;
  2513.                 break;
  2514.             case '$':
  2515.                 state = LOOK_FOR_MSGID;         /* user@host <foo $ */
  2516.                 break;
  2517.             default:
  2518.                 state = ERROR_STATE;            /* user@host foo */
  2519.             }
  2520.             break;
  2521.         case LOOK_FOR_MSGID:
  2522.             if(*cp == '\0')
  2523.                 break;
  2524.             msgid = cp;
  2525.             msgidlen++;
  2526.             state = IN_MSGID;
  2527.             break;
  2528.         case IN_MSGID:
  2529.             if(*cp == '\0')
  2530.                 state = FINAL_STATE;
  2531.             else
  2532.                 msgidlen++;
  2533.             break;
  2534.         default:
  2535.             /* what are we doing in this state? */
  2536.             state = ERROR_STATE;
  2537.         }
  2538.         if(*(cp) == '\0'){
  2539.             ++i;
  2540.             if(i < argc)
  2541.                 cp = argv[i];
  2542.             else
  2543.                 break;
  2544.         } else
  2545.             ++cp;
  2546.     }
  2547.     if(state == ERROR_STATE || state == LOOK_FOR_HOST
  2548.       || state == LOOK_FOR_FROM || state == LOOK_FOR_MSGID)
  2549.         return -1;              /* syntax error */
  2550.  
  2551.     m->to = mxallocw(userlen + hostlen + 2);
  2552.  
  2553.     strncpy(m->to, user, userlen);
  2554.     m->to[userlen] = '\0';
  2555.  
  2556.     if(hostlen){
  2557.         m->to[userlen] = '@';
  2558.         strncpy(m->to + userlen + 1, host, hostlen);
  2559.         m->to[userlen + hostlen + 1] = '\0';
  2560.     }
  2561.     if(fromlen){
  2562.         m->tofrom = mxallocw(fromlen + 1);
  2563.         strncpy(m->tofrom, from, fromlen);
  2564.         m->tofrom[fromlen] = '\0';
  2565.     }
  2566.     if(msgidlen){
  2567.         m->tomsgid = mxallocw(msgidlen + 1);
  2568.         strncpy(m->tomsgid, msgid, msgidlen);
  2569.         m->tomsgid[msgidlen] = '\0';
  2570.     }
  2571.     return 0;
  2572. }
  2573.  
  2574. /* This opens the data file and writes the mail header into it.
  2575.  * Returns 0 if OK, and -1 if not.
  2576.  */
  2577. static int near
  2578. mbx_data(m,cclist,extra)
  2579. struct mbx *m;
  2580. struct list *cclist;    /* list of carbon copy recipients */
  2581. char *extra;            /* optional extra header lines */
  2582. {
  2583.     struct list *ap;
  2584.     int cccnt = 0;
  2585.  
  2586.     if((m->tfile = temp_file(0,1)) == NULLFILE)
  2587.         return -1;
  2588.     fprintf(m->tfile,Hdrs[RECEIVED]);
  2589.     if(m->tofrom != NULLCHAR)
  2590.         fprintf(m->tfile,"from %s.bbs ",m->name);
  2591.     fprintf(m->tfile,"by %s (%s)\n\tid AA%ld; %s",
  2592.         Hostname, Version, get_msgid(), ptime(&currtime));
  2593.     fprintf(m->tfile,"%s%s",Hdrs[DATE],ptime(&currtime));
  2594.     fprintf(m->tfile,Hdrs[MSGID]);
  2595.     if(m->tomsgid)
  2596.         fprintf(m->tfile,"<%s@%s.bbs>\n", m->tomsgid, m->name);
  2597.     else
  2598.         fprintf(m->tfile,"<%ld@%s>\n",get_msgid(), Hostname);
  2599.     fprintf(m->tfile,Hdrs[FROM]);
  2600.     if(m->tofrom)
  2601.         fprintf(m->tfile,"%s%%%s.bbs@%s\n",m->tofrom, m->name, Hostname);
  2602.     else
  2603.         fprintf(m->tfile,"%s@%s\n", m->name, Hostname);
  2604.     fprintf(m->tfile,"%s%s\n",Hdrs[TO],m->origto != NULLCHAR ? m->origto : m->to);
  2605.     /* Write Cc: line */
  2606.     for(ap = cclist; ap != NULLLIST; ap = ap->next) {
  2607.         if(cccnt == 0){
  2608.             fprintf(m->tfile,"%s",Hdrs[CC]);
  2609.             cccnt = 4;
  2610.         }
  2611.         else {
  2612.             fprintf(m->tfile,", ");
  2613.             cccnt += 2;
  2614.         }
  2615.         if(cccnt + strlen(ap->val) > 80 - 3) {
  2616.             fprintf(m->tfile,"\n    ");
  2617.             cccnt = 4;
  2618.         }
  2619.         fputs(ap->val,m->tfile);
  2620.         cccnt += strlen(ap->val);
  2621.     }
  2622.     if(cccnt)
  2623.         fputc('\n',m->tfile);
  2624.     fprintf(m->tfile,"%s%s\n",Hdrs[SUBJECT],m->line);
  2625.     if(!isspace(m->stype) && ((m->stype != 'R' && m->stype != 'F') ||
  2626.       (m->sid & MBX_SID) !=0))
  2627.           fprintf(m->tfile,"%s%c\n", Hdrs[BBSTYPE],m->stype);
  2628.     if(extra != NULLCHAR)
  2629.         fprintf(m->tfile,extra);
  2630.     fputc('\n',m->tfile);
  2631.  
  2632.     return 0;
  2633. }
  2634.  
  2635. /* Returns true if string is in history file or if string appears to be a
  2636.  * message id generated by our system.
  2637.  */
  2638. static int near
  2639. msgidcheck(string)
  2640. char *string;
  2641. {
  2642.     FILE *fp;
  2643.     char buf[LINELEN], *cp;
  2644.  
  2645.     if(string == NULLCHAR)
  2646.         return 0;
  2647.     /* BID's that we have generated ourselves are not kept in the history
  2648.      * file. Such BID's are in the nnnn_hhhh form, where hhhh is a part of
  2649.      * our hostname, truncated so that the BID is no longer than 11
  2650.      * characters.
  2651.      */
  2652.     if((cp = strchr(string,'_')) != NULLCHAR && *(cp+1) != '\0' &&
  2653.       strnicmp(cp+1,Hostname,strlen(cp+1)) == 0)
  2654.         return 1;
  2655.  
  2656.     if((fp = fopen(Historyfile,READ_TEXT)) == NULLFILE)
  2657.         return 0;
  2658.     while(fgets(buf,LINELEN,fp) != NULLCHAR) {
  2659.         rip(buf);
  2660.         if(stricmp(string,buf) == 0) {  /* found */
  2661.             fclose(fp);
  2662.             return 1;
  2663.         }
  2664.     }
  2665.     fclose(fp);
  2666.     return 0;
  2667. }
  2668.  
  2669. /* Read the rewrite file for lines where the first word is a regular
  2670.  * expression and the second word are rewriting rules. The special
  2671.  * character '$' followed by a digit denotes the string that matched
  2672.  * a '*' character. The '*' characters are numbered from 1 to 9.
  2673.  * Example: the line "*@*.* $2@$1.ampr.org" would rewrite the address
  2674.  * "foo@bar.xxx" to "bar@foo.ampr.org".
  2675.  * $H is replaced by our hostname, and $$ is an escaped $ character.
  2676.  * If the third word on the line has an 'r' character in it, the function
  2677.  * will recurse with the new address.
  2678.  */
  2679. char *
  2680. rewrite_address(addr)
  2681. char *addr;
  2682. {
  2683.     char *argv[10], buf[MBXLINE], *cp, *cp2, *retstr;
  2684.     int cnt;
  2685.     FILE *fp;
  2686.  
  2687.     if ((fp = fopen(Rewritefile,READ_TEXT)) == NULLFILE)
  2688.         return NULLCHAR;
  2689.     memset((char *)argv,0,10*sizeof(char *));
  2690.     while(fgets(buf,MBXLINE,fp) != NULLCHAR) {
  2691.         if(*buf == '#')         /* skip commented lines */
  2692.             continue;
  2693.         if((cp = strchr(buf,' ')) == NULLCHAR) /* get the first word */
  2694.             if((cp = strchr(buf,'\t')) == NULLCHAR)
  2695.                 continue;
  2696.         *cp = '\0';
  2697.         if((cp2 = strchr(buf,'\t')) != NULLCHAR){
  2698.             *cp = ' ';
  2699.             cp = cp2;
  2700.             *cp = '\0';
  2701.         }
  2702.         if(!wildmat(addr,buf,argv))
  2703.             continue;               /* no match */
  2704.         rip(++cp);
  2705.         cp2 = retstr = (char *)mxallocw(MBXLINE);
  2706.         while(*cp != '\0' && *cp != ' ' && *cp != '\t')
  2707.             if(*cp == '$') {
  2708.                 if(isdigit(*(++cp)))
  2709.                     if(argv[*cp - '0'-1] != '\0')
  2710.                         strcat(cp2,argv[*cp - '0'-1]);
  2711.                 if(*cp == 'h' || *cp == 'H') /* Our hostname */
  2712.                     strcat(cp2,Hostname);
  2713.                 if(*cp == '$')  /* Escaped $ character */
  2714.                     strcat(cp2,"$");
  2715.                 cp2 = retstr + strlen(retstr);
  2716.                 cp++;
  2717.             }
  2718.             else
  2719.                 *cp2++ = *cp++;
  2720.         for(cnt=0; argv[cnt] != NULLCHAR; ++cnt)
  2721.             xfree(argv[cnt]);
  2722.         fclose(fp);
  2723.         /* If there remains an 'r' character on the line, repeat
  2724.          * everything by recursing.
  2725.          */
  2726.         if(strchr(cp,'r') != NULLCHAR || strchr(cp,'R') != NULLCHAR) {
  2727.             if((cp2 = rewrite_address(retstr)) != NULLCHAR) {
  2728.                 xfree(retstr);
  2729.                 return cp2;
  2730.             }
  2731.         }
  2732.         return retstr;
  2733.     }
  2734.     fclose(fp);
  2735.     return NULLCHAR;
  2736. }
  2737.  
  2738. /* uuencode a file -- translated from C++; both versions copyright 1990
  2739.    by David R. Evans, G4AMJ/NQ0I
  2740. */
  2741.  
  2742. static int near
  2743. uuencode(infile,s,infilename)
  2744. FILE *infile;
  2745. int s;                  /* output socket */
  2746. char *infilename;
  2747. {
  2748.   int n_read_so_far = 0, n_written_so_far = 0, in_chars, n, mode = 0755;
  2749.   unsigned long cnt = 0;
  2750.   unsigned char in[3], out[4], line[100];
  2751. #ifdef UNIX
  2752.   struct stat stb;
  2753.  
  2754.   if(stat(infilename,&stb) != -1)
  2755.        mode = stb.st_mode & 0777;       /* get real file protection mode */
  2756. #endif
  2757.  
  2758.   usprintf(s,"\nbegin %03o %s\n", mode, infilename);
  2759.  
  2760.   /* do the encode */
  2761.   while ((in_chars = fread(in, 1, 3, infile)) != 0) {
  2762.     out[0] = in[0] >> 2;
  2763.     out[1] = in[0] << 6;
  2764.     out[1] = out[1] >> 2;
  2765.     out[1] = out[1] | (in[1] >> 4);
  2766.     out[2] = in[1] << 4;
  2767.     out[2] = out[2] >> 2;
  2768.     out[2] = out[2] | (in[2] >> 6);
  2769.     out[3] = in[2] << 2;
  2770.     out[3] = out[3] >> 2;
  2771.     for (n = 0; n < 4; n++)
  2772.       out[n] += ' ';
  2773.     n_read_so_far += in_chars;
  2774.     for (n = 0; n < 4; n++)
  2775.       line[n_written_so_far++] = out[n];
  2776.     if ((in_chars != 3) || (n_written_so_far == 60)) {
  2777.       line[(n_read_so_far + 2) / 3 * 4] = '\0';
  2778.  
  2779.       usprintf(s,"%c%s\n",n_read_so_far + ' ', line);
  2780.       usflush(s);
  2781.       cnt += n_read_so_far;
  2782.       n_read_so_far = 0;
  2783.       n_written_so_far = 0;
  2784.     }
  2785.   }
  2786.  
  2787.   if (usprintf(s," \nend\nsize %lu\n\n", cnt) == EOF)
  2788.     return 1;
  2789.   return 0;
  2790. }
  2791.  
  2792. /* Attempt to determine if this is third-pary mail. */
  2793. static int
  2794. thirdparty(m)
  2795. struct mbx *m;
  2796. {
  2797.     if(strpbrk(m->to,"@%!") != NULLCHAR)
  2798.         return 0;
  2799.  
  2800.     if(stricmp(m->to,MBHostname) == 0)
  2801.         return -1;
  2802.  
  2803.     if(stricmp(m->to,"sysop") == 0)
  2804.         return -1;
  2805.  
  2806.     return(isarea(m->to));
  2807. }
  2808.  
  2809. /* Subroutine for setting and displaying unsigned integer variables */
  2810. int
  2811. setuns(var,label,argc,argv)
  2812. unsigned *var;
  2813. char *label;
  2814. int argc;
  2815. char *argv[];
  2816. {
  2817.     if(argc < 2)
  2818.         tprintf("%s: %u\n",label,*var);
  2819.     else
  2820.         *var = atoi(argv[1]);
  2821.  
  2822.     return 0;
  2823. }
  2824.  
  2825.  
  2826.